/*  $Id: misc-types.h,v 1.5 2009/10/31 02:02:05 sarrazip Exp $
    misc-types.h - Miscellaneous types used by the dictionary class.

    verbiste - French conjugation system
    Copyright (C) 2003-2005 Pierre Sarrazin <http://sarrazip.com/>

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
    as published by the Free Software Foundation; either version 2
    of the License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
    02111-1307, USA.
*/

#ifndef _H_misc_types
#define _H_misc_types

#include <verbiste/c-api.h>

#include <assert.h>
#include <vector>
#include <string>
#include <map>


/**
    Valid modes.
*/
enum Mode
{
    INVALID_MODE = VERBISTE_INVALID_MODE, 
    INFINITIVE_MODE = VERBISTE_INFINITIVE_MODE, 
    INDICATIVE_MODE = VERBISTE_INDICATIVE_MODE, 
    CONDITIONAL_MODE = VERBISTE_CONDITIONAL_MODE,
    SUBJUNCTIVE_MODE = VERBISTE_SUBJUNCTIVE_MODE, 
    IMPERATIVE_MODE = VERBISTE_IMPERATIVE_MODE, 
    PARTICIPLE_MODE = VERBISTE_PARTICIPLE_MODE
};


/**
    Valid tenses.
*/
enum Tense 
{
    INVALID_TENSE = VERBISTE_INVALID_TENSE, 
    PRESENT_TENSE = VERBISTE_PRESENT_TENSE, 
    PAST_TENSE = VERBISTE_PAST_TENSE, 
    IMPERFECT_TENSE = VERBISTE_IMPERFECT_TENSE, 
    FUTURE_TENSE = VERBISTE_FUTURE_TENSE
};



/**
    Description of a verb inflection.
    Gives the mode, tense and person of a conjugated verb.
    The person is 1, 2 or 3 for je/nous, tu/vous, il/ils, except in
    infinitive and participle mode, where it is always 0
    since it does not apply.
*/
class ModeTensePersonNumber
{
public:

    /** Mode (infinitive, indicative, etc). */
    Mode mode;

    /** Tense (present, past, etc). */
    Tense tense;

    /** Person (1, 2 or 3, or 0 in infinitive and participle modes). */
    unsigned char person;  // 1, 2 or 3, or 0 (invalid)

    /** Number (true for plural, false for singular). */
    bool plural;

    /** Indicates if this termination is correct or an error. */
    bool correct;


    ModeTensePersonNumber(Mode m = INVALID_MODE,
		    Tense t = INVALID_TENSE,
		    unsigned char pers = 0,
		    bool plur = false,
		    bool isCorrect = true)
      : mode(m), tense(t), person(pers), plural(plur), correct(isCorrect)
    {
	assert(mode <= PARTICIPLE_MODE);
	assert(tense <= FUTURE_TENSE);
	assert(person <= 3);
    }


    /** Constructs an object from English mode and tense names.
	Calls the set() method.
	@param	modeName	mode name known to method
				FrenchVerbDictionary::convertModeName()
	@param	tenseName	tense name known to method
				FrenchVerbDictionary::convertTenseName()
	@param	personNum	person "counter" (1--6, except for imperative
				mode, where it must be 1--3; ignored for
				infinitive and participle modes)
	@param	isCorrect	indicates if this termination is correct
				or an error
    */
    ModeTensePersonNumber(const char *modeName,
		    const char *tenseName,
		    int personNum,
		    bool isCorrect)
    {
	set(modeName, tenseName, personNum, isCorrect);
    }


    /** Initializes an object from English mode and tense names.
	Call the set() method.
	@param	modeName	mode name known to method
				FrenchVerbDictionary::convertModeName()
	@param	tenseName	tense name known to method
				FrenchVerbDictionary::convertTenseName()
	@param	personNum	person "counter" (1--6, except for imperative
				mode, where it must be 1--3; ignored for
				infinitive and participle modes)
	@param	isCorrect	indicates if this termination is correct
				or an error
    */
    void set(const char *modeName, const char *tenseName, int personNum, bool isCorrect);


    /**
	Dumps the fields of this object into those of the destination object.
	@param	destination	object whose fields (mode, tense, person,
				number) are assigned with values taken
				from this object
    */
    void dump(Verbiste_ModeTensePersonNumber &destination) const;
};


struct InflectionSpec
{
    std::string inflection;
    bool isCorrect;

    InflectionSpec(const std::string &inf, bool c) : inflection(inf), isCorrect(c) {}
};


/** List of inflections. */
typedef std::vector<InflectionSpec> PersonSpec;


/** List of persons (1, 3 or 6 persons depending on the mode and tense). */
typedef std::vector<PersonSpec> TenseSpec;


/**
    Mode specification.
    Contains tense specifications indexed by Tense values.
*/
typedef std::map<Tense, TenseSpec> ModeSpec;


/**
    Conjugation template specification.
    Contains mode specifications indexed by Mode values.
*/
typedef std::map<Mode, ModeSpec> TemplateSpec;


/**
    Conjugation system for the known verbs of a language.
    Contains conjugation templates indexed by template names.
*/
typedef std::map<std::string, TemplateSpec> ConjugationSystem;


/**
    Table of template names indexed by verb infinitive.
    If the verb "abaisser" follows the "aim:er" conjugation template,
    then a VerbTable would contain an entry where the key is "abaisser"
    and the value is "aim:er".
*/
typedef std::map<std::string, std::string> VerbTable;


/**
    Table that describes the mode, tense and person of a number of inflections.
    For example, in the "aim:er" conjugation template, the inflection
    (termination) "e" is associated with:

    - the 1st person singular of the indicative present;

    - the 3rd person singular of the indicative present;

    - the 1st person singular of the subjunctive present;

    - the 3rd person singular of the subjunctive present;

    - the 2nd person singular of the imperative present.

    Thus, in this table, the key "e" would be be associated with a vector
    of five objects representing these five mode-tense-person combinations.
*/
typedef std::map<std::string, std::vector<ModeTensePersonNumber> >
					    TemplateInflectionTable;


/**
    Table of template inflection tables, indexed by template names.
    For example, a key "aim:er" would be associated with a template
    inflection table that gives all inflections (terminations) that are
    accepted by the "aim:er" conjugation template (e.g., "e", "es",
    "ons", etc).
*/
typedef std::map<std::string, TemplateInflectionTable> InflectionTable;


/**
    Description of a conjugated verb's inflection.
*/
class InflectionDesc
{
public:

    /** Infinitive form of the conjugated verb (UTF-8). */
    std::string infinitive;

    /** Conjugated template used by the verb (e.g. "aim:er") (UTF-8). */
    std::string templateName;

    /** Mode, tense, person and number of the inflection. */
    ModeTensePersonNumber mtpn;

    /**
	Constructs an inflection description from optional arguments.
    */
    InflectionDesc(const std::string &inf = "",
		const std::string &tname = "",
		ModeTensePersonNumber m = ModeTensePersonNumber())
      : infinitive(inf),
	templateName(tname),
	mtpn(m)
    {
    }
};


#endif  /* _H_misc_types */
