/***************************************************************************
 *   Copyright (C) 2007 by Arnold Kraschinski                              *
 *   arnold.kra67@gmx.de                                                   *
 *                                                                         *
 *   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.,                                       *
 *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.          *
 ***************************************************************************/

#include "verbdata.h"

// Qt header files
//#include <QtAlgorithms>
#include <QDomDocument>
#include <QDomNodeList>
#include <QFile>
#include <QString>
#include <QDate>

// KDE header files
#include <kdebug.h>
#include <kstandarddirs.h>
#include <klocale.h>

// project header files
#include "kverbossettings.h"


/* -----------------------------------------------------------------------------------------------------
 * class Verb
 * -----------------------------------------------------------------------------------------------------
 */
const QString    Verb::REFLEXIV_PRONOUNS[6] = {"me", "te", "se", "nos", "os", "se"};
int              Verb::AMAR_OFFSET[NUMBER_OF_VERB_FORMS] = 
                                           {2, 1, 1, 1, 2, 1, 2, 1, 2, 1, 1, 0,
                                            0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 1, 1,
                                            0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2,
                                            0, 0, 0, 2, 0, 0, 1, 1, 1, 2, 1, 1,
                                            0, 0, 0, 2, 0, 0, 0, 1, 2, 2, 1, 2,
                                            1, 1, 1           };
QString          Verb::AMAR_ENDING[NUMBER_OF_VERB_FORMS] = 
                                           {QString::fromUtf8("o"), QString::fromUtf8("s"), QString::fromUtf8(""), QString::fromUtf8("mos"), QString::fromUtf8("áis"), QString::fromUtf8("n"),
                                            QString::fromUtf8("é"), QString::fromUtf8("ste"), QString::fromUtf8("ó"), QString::fromUtf8("mos"), QString::fromUtf8("steis"), QString::fromUtf8("on"),
                                            QString::fromUtf8("é"), QString::fromUtf8("ás"), QString::fromUtf8("á"), QString::fromUtf8("emos"), QString::fromUtf8("éis"), QString::fromUtf8("án"),
                                            QString::fromUtf8("ba"), QString::fromUtf8("bas"), QString::fromUtf8("ba"), QString::fromUtf8("ábamos"), QString::fromUtf8("bais"), QString::fromUtf8("ban"),
                                            QString::fromUtf8("ía"), QString::fromUtf8("ías"), QString::fromUtf8("ía"), QString::fromUtf8("íamos"), QString::fromUtf8("íais"), QString::fromUtf8("ían"),
                                            QString::fromUtf8("e"), QString::fromUtf8("es"), QString::fromUtf8("e"), QString::fromUtf8("emos"), QString::fromUtf8("éis"), QString::fromUtf8("en"),
                                            QString::fromUtf8("a"), QString::fromUtf8("as"), QString::fromUtf8("a"), QString::fromUtf8("áramos"), QString::fromUtf8("ais"), QString::fromUtf8("an"),
                                            QString::fromUtf8("se"), QString::fromUtf8("ses"), QString::fromUtf8("se"), QString::fromUtf8("ásemos"), QString::fromUtf8("seis"), QString::fromUtf8("sen"),
                                            QString::fromUtf8("e"), QString::fromUtf8("es"), QString::fromUtf8("e"), QString::fromUtf8("áremos"), QString::fromUtf8("eis"), QString::fromUtf8("en"),
                                            QString::fromUtf8(""), QString::fromUtf8(""), QString::fromUtf8("e"), QString::fromUtf8("emos"), QString::fromUtf8("d"), QString::fromUtf8("en"),
                                            QString::fromUtf8("ndo"), QString::fromUtf8("do"), QString::fromUtf8("do")             };
int              Verb::TEMER_OFFSET[NUMBER_OF_VERB_FORMS] =  
                                           {2, 1, 1, 1, 2, 1, 2, 2, 2, 2, 2, 2,
                                            0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2,
                                            0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2,
                                            2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
                                            2, 2, 2, 2, 2, 2, 0, 1, 2, 2, 1, 2,
                                            2, 2, 2           };
QString          Verb::TEMER_ENDING[NUMBER_OF_VERB_FORMS] =  
                                           {QString::fromUtf8("o"), QString::fromUtf8("s"), QString::fromUtf8(""), QString::fromUtf8("mos"), QString::fromUtf8("éis"), QString::fromUtf8("n"),
                                            QString::fromUtf8("í"), QString::fromUtf8("iste"), QString::fromUtf8("ió"), QString::fromUtf8("imos"), QString::fromUtf8("isteis"), QString::fromUtf8("ieron"),
                                            QString::fromUtf8("é"), QString::fromUtf8("ás"), QString::fromUtf8("á"), QString::fromUtf8("emos"), QString::fromUtf8("éis"), QString::fromUtf8("án"),
                                            QString::fromUtf8("ía"), QString::fromUtf8("ías"), QString::fromUtf8("ía"), QString::fromUtf8("íamos"), QString::fromUtf8("íais"), QString::fromUtf8("ían"),
                                            QString::fromUtf8("ía"), QString::fromUtf8("ías"), QString::fromUtf8("ía"), QString::fromUtf8("íamos"), QString::fromUtf8("íais"), QString::fromUtf8("ían"), 
                                            QString::fromUtf8("a"), QString::fromUtf8("as"), QString::fromUtf8("a"), QString::fromUtf8("amos"), QString::fromUtf8("áis"), QString::fromUtf8("an"),
                                            QString::fromUtf8("iera"), QString::fromUtf8("ieras"), QString::fromUtf8("iera"), QString::fromUtf8("iéramos"), QString::fromUtf8("ierais"), QString::fromUtf8("ieran"),
                                            QString::fromUtf8("iese"), QString::fromUtf8("ieses"), QString::fromUtf8("iese"), QString::fromUtf8("iésemos"), QString::fromUtf8("ieseis"), QString::fromUtf8("iesen"),
                                            QString::fromUtf8("iere"), QString::fromUtf8("ieres"), QString::fromUtf8("iere"), QString::fromUtf8("iéremos"), QString::fromUtf8("iereis"), QString::fromUtf8("ieren"),
                                            QString::fromUtf8(""), QString::fromUtf8(""), QString::fromUtf8("a"), QString::fromUtf8("amos"), QString::fromUtf8("d"), QString::fromUtf8("an"),
                                            QString::fromUtf8("iendo"), QString::fromUtf8("ido"), QString::fromUtf8("ido")         };
int              Verb::PARTIR_OFFSET[NUMBER_OF_VERB_FORMS] = 
                                           {2, 2, 2, 1, 2, 2, 2, 1, 1, 1, 1, 1,
                                            0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2,
                                            0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2,
                                            1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
                                            1, 1, 1, 1, 1, 1, 0, 2, 2, 2, 1, 2,
                                            1, 1, 1           };
QString          Verb::PARTIR_ENDING[NUMBER_OF_VERB_FORMS] = 
                                           {QString::fromUtf8("o"), QString::fromUtf8("es"), QString::fromUtf8("e"), QString::fromUtf8("mos"), QString::fromUtf8("ís"), QString::fromUtf8("en"),
                                            QString::fromUtf8("í"), QString::fromUtf8("ste"), QString::fromUtf8("ó"), QString::fromUtf8("mos"), QString::fromUtf8("steis"), QString::fromUtf8("eron"), 
                                            QString::fromUtf8("é"), QString::fromUtf8("ás"), QString::fromUtf8("á"), QString::fromUtf8("emos"), QString::fromUtf8("éis"), QString::fromUtf8("án"),
                                            QString::fromUtf8("ía"), QString::fromUtf8("ías"), QString::fromUtf8("ía"), QString::fromUtf8("íamos"), QString::fromUtf8("íais"), QString::fromUtf8("ían"), 
                                            QString::fromUtf8("ía"), QString::fromUtf8("ías"), QString::fromUtf8("ía"), QString::fromUtf8("íamos"), QString::fromUtf8("íais"), QString::fromUtf8("ían"),
                                            QString::fromUtf8("a"), QString::fromUtf8("as"), QString::fromUtf8("a"), QString::fromUtf8("amos"), QString::fromUtf8("áis"), QString::fromUtf8("an"), 
                                            QString::fromUtf8("era"), QString::fromUtf8("eras"), QString::fromUtf8("era"), QString::fromUtf8("éramos"), QString::fromUtf8("erais"), QString::fromUtf8("eran"),
                                            QString::fromUtf8("ese"), QString::fromUtf8("eses"), QString::fromUtf8("ese"), QString::fromUtf8("ésemos"), QString::fromUtf8("eseis"), QString::fromUtf8("esen"),
                                            QString::fromUtf8("ere"), QString::fromUtf8("eres"), QString::fromUtf8("ere"), QString::fromUtf8("éremos"), QString::fromUtf8("ereis"), QString::fromUtf8("eren"),
                                            QString::fromUtf8(""), QString::fromUtf8("e"), QString::fromUtf8("a"), QString::fromUtf8("amos"), QString::fromUtf8("d"), QString::fromUtf8("an"),
                                            QString::fromUtf8("endo"), QString::fromUtf8("do"), QString::fromUtf8("do")             };
const int                 Verb::NUMBER_OF_FORMS = NUMBER_OF_VERB_FORMS;
QString                   Verb::ENDING[4] = {"ar", "er", "ir", QString::fromUtf8("ír")};
const int                 Verb::ENDING_AR = 0;
const int                 Verb::ENDING_ER = 1;
const int                 Verb::ENDING_IR = 2;
const int                 Verb::ENDING_IR2 = 3;

const int                 Verb::MAXLEVEL = MAXLEVELS;
const int                 Verb::UNTRAINED = 0;
const int                 Verb::TRAINED = 2;
const int                 Verb::WELLKNOWN = 3;
const int                 Verb::VERYWELLKNOWN = 4;
const int                 Verb::SECUREDKNOWLEDGE = 5;
const QString             Verb::LEVELNAMES[ LEVEL_ARRAY_SIZE ] = {"untrained", "first step", "trained", "well known", "good knowledge", "secured knowledge", "secured knowledge 2", "secured knowledge 3"};
int                       Verb::LEVEL_BLOCK_DAYS[LEVEL_ARRAY_SIZE] = { 0, 1, 2, 4, 7, 14, 30, 60 };
int                       Verb::LEVEL_EXPIRE_DAYS[LEVEL_ARRAY_SIZE] = { 0, 2, 4, 7, 14, 30, 60, 120 };
const int                 Verb::FOREVER = 0;


Verb::Verb() 
: m_infinitive(""), m_reflexive(false), m_family(0), m_comment(""), m_option(""), m_selected(false),  m_level(0),m_lastDay(0)
{
}

Verb::Verb(QString infinitive, bool reflexive, int family, QString comment, QString option) 
: m_infinitive(infinitive), m_reflexive(reflexive), m_family(family), m_comment(comment), m_option(option), m_selected(false),  m_level(0), m_lastDay(0)
{
}

Verb::~Verb() {
}

int Verb::endingNumber() 
{
    return endingNumber(m_infinitive);
}

void Verb::setSelected(bool selected)
{
    m_selected = selected;
    m_level = 0;
    m_lastDay = 0;
}

void Verb::setLevel(int level)
{
    if ( !m_selected ) {
        m_level = 0;
        m_lastDay = 0;
    } else {
        m_level = ( level < 0 ) ? 0 : ( ( level > MAXLEVEL) ? MAXLEVEL : level );
        m_lastDay = ( level == 0 ) ? 0 : QDate::currentDate().toJulianDay() + LEVEL_EXPIRE_DAYS[m_level];
    }
}

void Verb::levelUp()
{
    setLevel( m_level + 1 );
}

void Verb::levelDown()
{
    setLevel( m_level - 1 );
}

void Verb::setStatus( bool selected, int level, int lastDay )
{
    m_selected = selected;
    if ( !selected) {
        m_level = 0;
        m_lastDay = 0;
    } else {
        m_level = ( level < 0 ) ? 0 : ( ( level > MAXLEVEL) ? MAXLEVEL : level );
        m_lastDay = ( m_level == 0 ) ? 0 : lastDay;
    }
}

bool Verb::blocked()
{
    if (m_level == 0) {
        return false;
    }
    if ( m_lastDay - LEVEL_EXPIRE_DAYS[m_level] + LEVEL_BLOCK_DAYS[m_level] < QDate::currentDate().toJulianDay() ) {
        return true;
    } else {
        return false;
    }
}

bool Verb::expired()
{
    if (m_level == 0) {
        return false;
    }
    if ( m_lastDay  < QDate::currentDate().toJulianDay() ) {
        return true;
    } else {
        return false;
    }
}

bool Verb::isSmallerThan(QString v) const
{
    return (QString::localeAwareCompare(infinitive(), v) < 0) ? true : false;
}

bool Verb::operator<(const Verb& v) const 
{
    return (QString::localeAwareCompare(infinitive(), v.infinitive()) < 0) ? true : false;
}

QVector<QString> Verb::buildForms(int offset[], QString ending[], bool html) 
{
    QString tag1 = (html) ? "<span id=""ending"">" : "";
    QString tag2 = (html) ? "</span>" : "";
    QVector<QString> forms;
    for (int i = 0; i < NUMBER_OF_FORMS; i++) {
        forms.push_back(m_infinitive.left(m_infinitive.length() - offset[i]) + tag1 + ending[i] + tag2);
    }
    return forms;
}

int Verb::endingNumber(QString infinitive) 
{
    int r = -1;
    for (int i = 0; i < 4; i++) {
        if (infinitive.endsWith(ENDING[i])) {
            r = i;
        }
    }
    if (-1 == r) {
        kDebug() << "Couldn't find the ending of the verb." << endl;
        kDebug() << ENDING[0] << ENDING[1] << ENDING[2] << ENDING[3] << endl;
    }
    return r;
}

/* -----------------------------------------------------------------------------------------------------
 * class VerbRegular
 * -----------------------------------------------------------------------------------------------------
 */
VerbRegular::VerbRegular() 
: Verb("", false, 0, "", "")
{
}

VerbRegular::VerbRegular(QString infinitive, bool reflexive, int family, QString comment, QString option) 
: Verb(infinitive, reflexive, family, comment, option)
{
}

VerbRegular::~VerbRegular() {
}


/* -----------------------------------------------------------------------------------------------------
 * class VerbRegularAR
 * -----------------------------------------------------------------------------------------------------
 */
VerbRegularAR::VerbRegularAR() 
: VerbRegular("-ar", false, 3 , "", "")
{
}

VerbRegularAR::VerbRegularAR(QString infinitive, bool reflexive, int family, QString comment, QString option) 
: VerbRegular(infinitive, reflexive, family, comment, option)
{
}

VerbRegularAR::~VerbRegularAR() {
}

QVector<QString> VerbRegularAR::conjugate(bool html) 
{
    return buildForms(AMAR_OFFSET, AMAR_ENDING, html);
}


/* -----------------------------------------------------------------------------------------------------
 * class VerbER
 * -----------------------------------------------------------------------------------------------------
 */
VerbRegularER::VerbRegularER() 
: VerbRegular("-er", false, 4 , "", "")
{
}

VerbRegularER::VerbRegularER(QString infinitive, bool reflexive, int family, QString comment, QString option) 
: VerbRegular(infinitive, reflexive, family, comment, option)
{
}

VerbRegularER::~VerbRegularER() {
}

QVector<QString> VerbRegularER::conjugate(bool html) {
    return buildForms(TEMER_OFFSET, TEMER_ENDING, html);
}


/* -----------------------------------------------------------------------------------------------------
 * class VerbIR
 * -----------------------------------------------------------------------------------------------------
 */
VerbRegularIR::VerbRegularIR() 
: VerbRegular("-ir", false, 5 , "", "")
{
}

VerbRegularIR::VerbRegularIR(QString infinitive, bool reflexive, int family, QString comment, QString option) 
: VerbRegular(infinitive, reflexive, family, comment, option)
{
}

VerbRegularIR::~VerbRegularIR() {
}

QVector<QString> VerbRegularIR::conjugate(bool html) {
    return buildForms(PARTIR_OFFSET, PARTIR_ENDING, html);
}


/* -----------------------------------------------------------------------------------------------------
 * class VerbIrregular
 * -----------------------------------------------------------------------------------------------------
 */
VerbIrregular::VerbIrregular() 
: Verb("", false, 0, "", "")
{
}

VerbIrregular::VerbIrregular(QString infinitive, bool reflexive, int family, QString comment, QString option) 
: Verb(infinitive, reflexive, family, comment, option)
{
}

VerbIrregular::~VerbIrregular() {
}

void VerbIrregular::addIrregularForm(int index, int offset, QString ending) {
    IrregularPattern form;
    form.index = index;
    form.offset = offset;
    form.ending = ending;
    m_irregularForm.push_back(form);
}


/* -----------------------------------------------------------------------------------------------------
 * class VerbIrregularAR
 * -----------------------------------------------------------------------------------------------------
 */
VerbIrregularAR::VerbIrregularAR() 
: VerbIrregular("-ar", false, -1 , "", "")
{
}

VerbIrregularAR::VerbIrregularAR(QString infinitive, bool reflexive, int family, QString comment, QString option) 
: VerbIrregular(infinitive, reflexive, family, comment, option)
{
}

VerbIrregularAR::~VerbIrregularAR() {
}

QVector<QString> VerbIrregularAR::conjugate(bool html) {
    QString tag1 = (html) ? "<span id=""ending"">" : "";
    QString tag2 = (html) ? "</span>" : "";
    QVector<QString> forms = buildForms(AMAR_OFFSET, AMAR_ENDING, html);
    int n = m_irregularForm.size();
    for (int i = 0; i < n; i++) {
        int index = m_irregularForm[i].index;
        int offset = m_irregularForm[i].offset;
        QString ending = m_irregularForm[i].ending;
        forms[index] = m_infinitive.left(m_infinitive.length() - offset) + tag1 + ending + tag2;
    }
    return forms;
}


/* -----------------------------------------------------------------------------------------------------
 * class VerbIrregularCAR
 * -----------------------------------------------------------------------------------------------------
 */
int              VerbIrregularCAR::CAR_INDEX[10] = {6, 30, 31, 32, 33, 34, 35, 56, 57, 59};
QString          VerbIrregularCAR::CAR_ENDING[10] = {QString::fromUtf8("qué"), QString::fromUtf8("que"),
                                                     QString::fromUtf8("ques"), QString::fromUtf8("que"),
                                                     QString::fromUtf8("quemos"), QString::fromUtf8("quéis"),
                                                     QString::fromUtf8("quen"), QString::fromUtf8("que"),
                                                     QString::fromUtf8("quemos"), QString::fromUtf8("quen") };

VerbIrregularCAR::VerbIrregularCAR() 
: VerbIrregularAR("-ar", false, -1 , "", "")
{
}

VerbIrregularCAR::VerbIrregularCAR(QString infinitive, bool reflexive, int family, QString comment, QString option) 
: VerbIrregularAR(infinitive, reflexive, family, comment, option)
{
}

VerbIrregularCAR::~VerbIrregularCAR() {
}

QVector<QString> VerbIrregularCAR::conjugate(bool html) 
{
    QString tag1 = (html) ? "<span id=""ending"">" : "";
    QString tag2 = (html) ? "</span>" : "";
    QVector<QString> forms = VerbIrregularAR::conjugate(html);
    for (int i = 0; i < 10; i++) {
        // the offset for the -car forms is always 3!
        forms[CAR_INDEX[i]] = m_infinitive.left(m_infinitive.length() - 3) + tag1 + CAR_ENDING[i] + tag2;
    }
    return forms;
}


/* -----------------------------------------------------------------------------------------------------
 * class VerbIrregularGAR
 * -----------------------------------------------------------------------------------------------------
 */
int              VerbIrregularGAR::GAR_INDEX[10] = {6, 30, 31, 32, 33, 34, 35, 56, 57, 59};
QString          VerbIrregularGAR::GAR_ENDING[10] = {QString::fromUtf8("ué"), QString::fromUtf8("ue"),
                                                     QString::fromUtf8("ues"), QString::fromUtf8("ue"),
                                                     QString::fromUtf8("uemos"), QString::fromUtf8("uéis"),
                                                     QString::fromUtf8("uen"), QString::fromUtf8("ue"), 
                                                     QString::fromUtf8("uemos"), QString::fromUtf8("uen") };

VerbIrregularGAR::VerbIrregularGAR() 
: VerbIrregularAR("-ar", false, -1 , "", "")
{
}

VerbIrregularGAR::VerbIrregularGAR(QString infinitive, bool reflexive, int family, QString comment, QString option) 
: VerbIrregularAR(infinitive, reflexive, family, comment, option)
{
}

VerbIrregularGAR::~VerbIrregularGAR() {
}

QVector<QString> VerbIrregularGAR::conjugate(bool html) 
{
    QString tag1 = (html) ? "<span id=""ending"">" : "";
    QString tag2 = (html) ? "</span>" : "";
    QVector<QString> forms = VerbIrregularAR::conjugate(html);
    for (int i = 0; i < 10; i++) {
        // the offset for the -gar forms is always 2!
        forms[GAR_INDEX[i]] = m_infinitive.left(m_infinitive.length() - 2) + tag1 + GAR_ENDING[i] + tag2;
    }
    return forms;
}


/* -----------------------------------------------------------------------------------------------------
 * class VerbIrregularZAR
 * -----------------------------------------------------------------------------------------------------
 */
int              VerbIrregularZAR::ZAR_INDEX[10] = {6, 30, 31, 32, 33, 34, 35, 56, 57, 59};
QString          VerbIrregularZAR::ZAR_ENDING[10] = {QString::fromUtf8("cé"), QString::fromUtf8("ce"),
                                                     QString::fromUtf8("ces"), QString::fromUtf8("ce"),
                                                     QString::fromUtf8("cemos"), QString::fromUtf8("céis"), 
                                                     QString::fromUtf8("cen"), QString::fromUtf8("ce"), 
                                                     QString::fromUtf8("cemos"), QString::fromUtf8("cen") };

VerbIrregularZAR::VerbIrregularZAR() 
: VerbIrregularAR("-zar", false, -1 , "", "")
{
}

VerbIrregularZAR::VerbIrregularZAR(QString infinitive, bool reflexive, int family, QString comment, QString option) 
: VerbIrregularAR(infinitive, reflexive, family, comment, option)
{
}

VerbIrregularZAR::~VerbIrregularZAR() {
}

QVector<QString> VerbIrregularZAR::conjugate(bool html) 
{
    QString tag1 = (html) ? "<span id=""ending"">" : "";
    QString tag2 = (html) ? "</span>" : "";
    QVector<QString> forms = VerbIrregularAR::conjugate(html);
    for (int i = 0; i < 10; i++) {
        // the offset for the -car forms is always 3!
        forms[ZAR_INDEX[i]] = m_infinitive.left(m_infinitive.length() - 3) + tag1 + ZAR_ENDING[i] + tag2;
    }
    return forms;
}


/* -----------------------------------------------------------------------------------------------------
 * class VerbIrregularER
 * -----------------------------------------------------------------------------------------------------
 */
VerbIrregularER::VerbIrregularER() 
: VerbIrregular("-er", false, -1 , "", "")
{
}

VerbIrregularER::VerbIrregularER(QString infinitive, bool reflexive, int family, QString comment, QString option) 
: VerbIrregular(infinitive, reflexive, family, comment, option)
{
}

VerbIrregularER::~VerbIrregularER() {
}

QVector<QString> VerbIrregularER::conjugate(bool html) 
{
    QString tag1 = (html) ? "<span id=""ending"">" : "";
    QString tag2 = (html) ? "</span>" : "";
    QVector<QString> forms = buildForms(TEMER_OFFSET, TEMER_ENDING, html);
    int n = m_irregularForm.size();
    for (int i = 0; i < n; i++) {
        int index = m_irregularForm[i].index;
        int offset = m_irregularForm[i].offset;
        QString ending = m_irregularForm[i].ending;
        forms[index] = m_infinitive.left(m_infinitive.length() - offset) + tag1 + ending + tag2;
    }
    return forms;
}


/* -----------------------------------------------------------------------------------------------------
 * class VerbIrregularIR
 * -----------------------------------------------------------------------------------------------------
 */
VerbIrregularIR::VerbIrregularIR() 
: VerbIrregular("-ir", false, -1 , "", "")
{
}

VerbIrregularIR::VerbIrregularIR(QString infinitive, bool reflexive, int family, QString comment, QString option) 
: VerbIrregular(infinitive, reflexive, family, comment, option)
{
}

VerbIrregularIR::~VerbIrregularIR() {
}

QVector<QString> VerbIrregularIR::conjugate(bool html) 
{
    QString tag1 = (html) ? "<span id=""ending"">" : "";
    QString tag2 = (html) ? "</span>" : "";
    QVector<QString> forms = buildForms(PARTIR_OFFSET, PARTIR_ENDING, html);
    int n = m_irregularForm.size();
    for (int i = 0; i < n; i++) {
        int index = m_irregularForm[i].index;
        int offset = m_irregularForm[i].offset;
        QString ending = m_irregularForm[i].ending;
        forms[index] = m_infinitive.left(m_infinitive.length() - offset) + tag1 + ending + tag2;
    }
    return forms;
}


/* -----------------------------------------------------------------------------------------------------
 * class Verbdata
 * -----------------------------------------------------------------------------------------------------
 */
QList<Verb*>*       Verbdata::m_verbdata = 0;

const int Verbdata::GROUPS = GROUPCOUNT;
const QString Verbdata::GROUPNAMES[GROUPCOUNT] = {/*  0 */  i18n("regular -ar verb"),
                                                  /*  1 */  i18n("regular -er verb"),
                                                  /*  2 */  i18n("regular -ir verb"),
                                                  /*  3 */  i18n("group verbs e --> ie"),
                                                  /*  4 */  i18n("group verbs o --> ue"),
                                                  /*  5 */  i18n("group verbs e --> i"), 
                                                  /*  6 */  i18n("group verbs c --> qu"), 
                                                  /*  7 */  i18n("group verbs g --> gu"), 
                                                  /*  8 */  i18n("group verbs z --> c"),
                                                  /*  9 */  i18n("group verbs gu --> g"),
                                                  /* 10 */  i18n("group verbs c --> z"),
                                                  /* 11 */  i18n("group verbs g --> j"),
                                                  /* 12 */  i18n("group verbs gu --> g"),
                                                  /* 13 */  i18n("group verbs qu --> c"),
                                                  /* 14 */  i18n("with orthographic exceptions"),
                                                  /* 15 */  i18n("irregular verbs")};
const int Verbdata::FAMILIES = FAMILIES_COUNT;
// The families 0 and 70 don't exist. Therefore the value at position 0 and 70 is -1
const int Verbdata::GROUPMATCH[FAMILIES_COUNT] = {-1, 15, 15, 0, 1, 2, 5, 14, 15, 14,
                                                  15, 3, 15, 3, 15, 15, 15, 15, 15, 4,
                                                  15, 15, 4, 15, 15, 4, 15, 15, 15, 15,
                                                  15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
                                                  15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 
                                                  15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
                                                  15, 4, 15, 15, 15, 15, 15, 15, 15, 15,
                                                  -1, 6, 7, 8, 15, 14, 14, 9, 15, 15, 
                                                  15, 15, 15, 10, 11, 10, 11, 12, 13, 15,
                                                  15};

const int     Verbdata::TENSES = TRAINING_TENSES;
const int     Verbdata::IMPERATIVO = 8;
const QString Verbdata::TENSEINFO[TRAINING_TENSES][3] = 
       { /* The simple tenses */
         { QString::fromUtf8("Presente"), "0", "0" },
         { QString::fromUtf8("Pretérito Imperfecto"), "0", "3" },
         { QString::fromUtf8("Pretérito Indefinido"), "0", "1" },
         { QString::fromUtf8("Futuro Imperfecto"), "0", "2" },
         { QString::fromUtf8("Conditional Simple"), "0", "4" },
         { QString::fromUtf8("Subjuntivo Presente"), "0", "5" },
         { QString::fromUtf8("Subjuntivo Pretérito Imperfecto"), "0", "6" },       /* 2 versions!  Number: 6*/
         { QString::fromUtf8("Subjuntivo Futuro Imperfecto"), "0", "8" },
         { QString::fromUtf8("Imperativo"), "0", "9" },

         /* Tenses: form of 'haber' + partizipio */
         { QString::fromUtf8("Pretérito Perfecto"), "1", "0" },
         { QString::fromUtf8("Pretérito Pluscuamperfecto"), "1", "3" },
         { QString::fromUtf8("Pretérito Anterior"), "1", "1" },
         { QString::fromUtf8("Futuro Perfecto"), "1", "2" },
         { QString::fromUtf8("Conditional Perfecto"), "1", "4" },
         { QString::fromUtf8("Subjuntivo Pretérito Perfecto"), "1", "5" },
         { QString::fromUtf8("Subjuntivo Pretérito Pluscuamperfecto"), "1", "6" }, /* 2 versions! Number: 15 */
         { QString::fromUtf8("Subjuntivo Futuro Perfecto"), "1", "8" },

         /* Tenses: form of 'estar' + gerundio */
         { QString::fromUtf8("Gerundio Presente"), "2", "0" }, 
         { QString::fromUtf8("Gerundio Imperfecto"), "2", "3" },
         { QString::fromUtf8("Gerundio Pretérito"), "2", "1" },
         { QString::fromUtf8("Gerundio Futuro"), "2", "2" },
         { QString::fromUtf8("Gerundio Conditional"), "2", "4" }      };


Verbdata::Verbdata() {
}

// The verbs aren't QObjects so delete them.
Verbdata::~Verbdata() {
    if (!m_verbdata->isEmpty()) {
        for (QList<Verb*>::iterator it = m_verbdata->begin(); it < m_verbdata->end(); it++) {
            Verb* v = *it;
            delete v;
        }
        m_verbdata->clear();
    }
}

int Verbdata::count() {
    if (m_verbdata == 0) {
        readVerbdataFile();
    }
    return m_verbdata->size();
}

QList<Verb*>* Verbdata::getVerblist() {
    if (m_verbdata == 0) {
        readVerbdataFile();
    }
    return m_verbdata;
}

QStringList Verbdata::getInfinitiveList() {
    if (m_verbdata == 0) {
        readVerbdataFile();
    }
    QStringList infinitives;
    for (QList<Verb*>::iterator it = m_verbdata->begin(); it < m_verbdata->end(); it++) {
        infinitives.append( (*it)->infinitive() );
    }
    return infinitives;
}

QList<Verb*> Verbdata::verbPointers( bool selection )
{
    QList<Verb*> v;
    if ( selection ) {
        for (QList<Verb*>::iterator it = m_verbdata->begin(); it < m_verbdata->end(); it++) {
            if ( (*it)->selected() ) {
                v.append( *it );
            }
        }
    } else {
        v = *m_verbdata;
    }
    return v;
}

QVector<QString> Verbdata::conjugate(QString infinitive, bool html) {
    if (m_verbdata == 0) {
        readVerbdataFile();
    }
    QVector<QString> forms;
    Verb* v = find(infinitive);
    if (0 == v) {
        kDebug() << "Couldn't find the verb in the list." << endl;
    } else {
        forms = v->conjugate(html);
        //kDebug() << "Forms of the verb: " << infinitive << endl;
        //for (int i = 0; i < forms.size(); i++) {
        //    kDebug() << forms[i] << endl;
        //}
        //kDebug() << "end: " << infinitive << endl;
    }
    return forms;
}

Verb* Verbdata::find(const QString infinitive)
{
    if (m_verbdata == 0) {
        readVerbdataFile();
    }
    int left = 0;
    int right = m_verbdata->count() - 1;
    while (left <= right) {
        int middle = (left + right) / 2;
        if (m_verbdata->at(middle)->infinitive() == infinitive)
            return m_verbdata->at(middle);
        if (m_verbdata->at(middle)->isSmallerThan(infinitive)) {
            left = middle + 1;
        } else {
            right = middle - 1;
        }
    }
    return 0;
}

void Verbdata::readSettings()
{
    if (m_verbdata == 0) {
        readVerbdataFile();
    }
    bool changed(false);
    QStringList verbs = KVerbosSettings::verbselection();
    for (QStringList::iterator it = verbs.begin(); it < verbs.end(); it++) {
        QString v = *it;
        QStringList parts = v.split("=");
        Verb* verb = Verbdata::find(parts.at(0));
        if (verb == 0) {
            kDebug() << "Didn't find the verb: " << *it << endl;
        } else {
            int lastDay = parts.at(2).toInt();
            int level = parts.at(1).toInt();
            if ( ( level > 0 ) && ( QDate::currentDate().toJulianDay() > lastDay ) ) {
                kDebug() << "The verb " << verb->infinitive() << " has expired. It was moved from level " << level << " to level " << level - 1 << endl;
                verb->setSelected( true );
                level--;
                verb->setLevel( level );
                changed = true;
            } else {
                verb->setStatus( true, level, lastDay );
            }
        }
    }
    if (changed)
        writeSettings();
}

void Verbdata::writeSettings()
{
    QList<Verb*> verbs = verbPointers( true );
    QStringList l;
    for (QList<Verb*>::iterator it = verbs.begin(); it < verbs.end(); it++) {
        l << ((*it)->infinitive() + "=" + QString::number((*it)->level()) + "=" + QString::number((*it)->lastDay()));
    }
    KVerbosSettings::setVerbselection( l );
    KVerbosSettings::self()->writeConfig();
}

void Verbdata::reportTraining(Verb* verb, bool correct, bool apply)
{
    if (apply && !verb->blocked() ) {
        if (correct) {
            verb->levelUp();
            //kDebug() << "The verb " << verb->infinitive() << " was brought to the next level " << verb->level();
        } else {
            verb->levelDown();
            //kDebug() << "The verb " << verb->infinitive() << " was brought to the lower level " << verb->level();
        }
    }
}

void Verbdata::reportTraining(QString infinitive, bool correct, bool apply)
{
    reportTraining( find( infinitive ), correct, apply);
}

bool Verbdata::readVerbdataFile() {
    QDomDocument verbdata;
    QFile verbFile(KStandardDirs::locate("appdata", "data/verbdata.xml"));
    if (!verbFile.open(QIODevice::ReadOnly)) {
        kDebug() << "Cannot open the verbdata.xml file." << endl;
        return false;
    } else if ( !verbdata.setContent( &verbFile ) ) {
        kDebug() << "Cannot parse the verbdata.xml file." << endl;
        return false;
    } else {
        verbFile.close();
        m_verbdata = new QList<Verb*>();
        QDomNodeList verbs = verbdata.elementsByTagName("v");
        kDebug() << "There are: " << verbs.length() << " verbs in the list." << endl;

        int n = verbs.length();
        for (int i = 0; i < n; i++) {
            QDomElement elem = verbs.item(i).toElement();
            if (!elem.isNull()) {
                Verb* newVerb = 0;
                QString infinitive = elem.attribute("i");
                bool reflexive = (elem.attribute("r") == "1");
                int family = elem.attribute("f").toInt();
                QString comment = elem.attribute("c");
                QString option = elem.attribute("o");

                switch (family) {
                    case 3:
                        if (elem.hasChildNodes()) {
                            newVerb = new VerbIrregularAR(infinitive, reflexive, family, comment, option);
                        } else {
                            newVerb = new VerbRegularAR(infinitive, reflexive, family, comment, option);
                        }
                        break;
                    case 4:
                        if (elem.hasChildNodes()) {
                            newVerb = new VerbIrregularER(infinitive, reflexive, family, comment, option);
                        } else {
                            newVerb = new VerbRegularER(infinitive, reflexive, family, comment, option);
                        }
                        break;
                    case 5:
                        if (elem.hasChildNodes()) {
                            newVerb = new VerbIrregularIR(infinitive, reflexive, family, comment, option);
                        } else {
                            newVerb = new VerbRegularIR(infinitive, reflexive, family, comment, option);
                        }
                        break;
                    case 71:
                        newVerb = new VerbIrregularCAR(infinitive, reflexive, family, comment, option);
                        break;
                    case 72:
                        newVerb = new VerbIrregularGAR(infinitive, reflexive, family, comment, option);
                        break;
                    case 73:
                        newVerb = new VerbIrregularZAR(infinitive, reflexive, family, comment, option);
                        break;
                    default:
                        // 
                        // desembalar, hispir
                        //kDebug() << "An irregular verb that hasn't got any irregular form: " << infinitive << " " << family << endl;
                        int e = Verb::endingNumber(infinitive);
                        switch (e) {
                            case Verb::ENDING_AR:
                                newVerb = new VerbIrregularAR(infinitive, reflexive, family, comment, option);
                                break;
                            case Verb::ENDING_ER:
                                newVerb = new VerbIrregularER(infinitive, reflexive, family, comment, option);
                                break;
                            case Verb::ENDING_IR:
                            case Verb::ENDING_IR2:
                                newVerb = new VerbIrregularIR(infinitive, reflexive, family, comment, option);
                                break;
                            default:
                                kDebug() << "Couldn't determin the verb class" << endl;
                        }
                }
                if (elem.hasChildNodes()) {
                    VerbIrregular* v = dynamic_cast<VerbIrregular*>(newVerb);
                    if (v == 0) {
                        kDebug() << "We have a problem, a regular verb with irregular forms. " << newVerb->infinitive() << endl;
                    } else {
                        QDomElement child = elem.firstChildElement("sf");
                        while (!child.isNull()) {
                            int index = child.attribute("in").toInt();
                            QString ending = child.attribute("en");
                            int offset = child.attribute("o").toInt();
                            v->addIrregularForm(index, offset, ending);
                            child = child.nextSiblingElement("sf");
                        }
                    }
                }

                if (0 == newVerb) {
                    kDebug() << "Attention! The following verb couldn't be created: " << infinitive << " " << family << endl;
                } else {
                    int pos = m_verbdata->size();
                    if (pos == 0) {
                        m_verbdata->append(newVerb);
                    } else {
                        while ((pos > 0) && ( (*newVerb) < (*m_verbdata->at(pos - 1)) )) {
                            pos--;
                        }
                        m_verbdata->insert(pos, newVerb);
                    }
                }
            }
        }
        return true;
    }
}


