/***************************************************************************
 *   Copyright (C) 2004, 2007 by Kraschinski Arnold                        *
 *   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.          *
 ***************************************************************************/

// standard C++ headers
#include <stdlib.h>

// Qt header files
#include <QLineEdit>
#include <QVector>
#include <QPalette>
#include <QBrush>
#include <QColor>

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

// project header files
#include "formstrainer.h"
#include "kverbossettings.h"
#include "verbdata.h"
#include "qlearning.h"


const int          FormsTrainer::EXPECTING_INPUT = 0;
const int          FormsTrainer::CORRECTED = 1;
const int          FormsTrainer::CORRECT_FORMS = 2;
const int          FormsTrainer::SOLVED = 3;


FormsTrainer::FormsTrainer(QWidget *parent)
 : Trainer(parent)
{
    setupUi( this );
    m_learning = (QLearning*)parent;
    
    m_oldPalette = editVerb->palette();
    m_redPalette = m_oldPalette;
    m_redPalette.setBrush( QPalette::Text, QBrush( Qt::red ) );
    
    setFocusProxy( editVerb );
    
    m_formEdit[0][0] = edit_1_1;
    m_formEdit[0][1] = edit_1_2;
    m_formEdit[0][2] = edit_1_3;
    m_formEdit[0][3] = edit_1_4;
    m_formEdit[0][4] = edit_1_5;
    m_formEdit[0][5] = edit_1_6;
    
    m_formEdit[1][0] = edit_2_1;
    m_formEdit[1][1] = edit_2_2;
    m_formEdit[1][2] = edit_2_3;
    m_formEdit[1][3] = edit_2_4;
    m_formEdit[1][4] = edit_2_5;
    m_formEdit[1][5] = edit_2_6;
    
    m_formEdit[2][0] = edit_3_1;
    m_formEdit[2][1] = edit_3_2;
    m_formEdit[2][2] = edit_3_3;
    m_formEdit[2][3] = edit_3_4;
    m_formEdit[2][4] = edit_3_5;
    m_formEdit[2][5] = edit_3_6;
    
    connect( editVerb, SIGNAL( textEdited(QString) ), this, SLOT( slotTextEdited(QString) ) );
    connect( editVerb, SIGNAL( returnPressed() ), this, SLOT( slotReturnPressed() ) );
    connect( editTranslation, SIGNAL( textEdited(QString) ), this, SLOT( slotTextEdited(QString) ) );
    connect( editTranslation, SIGNAL( returnPressed() ), this, SLOT( slotReturnPressed() ) );
    for (int i = 0; i < 6; i++) {
        connect( m_formEdit[2][i], SIGNAL( textEdited(QString) ), this, SLOT( slotDuplicate(QString) ) );
    }
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 6; j++) {
            connect( m_formEdit[i][j], SIGNAL( textEdited(QString) ), this, SLOT( slotTextEdited(QString) ) );
            connect( m_formEdit[i][j], SIGNAL( returnPressed() ), this, SLOT( slotReturnPressed() ) );
        }
    }
}


FormsTrainer::~FormsTrainer()
{
}

bool FormsTrainer::setExercise()
{
    clearLineEdit();

    // select a tense and display it in the label
    m_tense = m_tenses[ rand() % m_tenses.size() ];
    labelTime->setText( Verbdata::TENSEINFO[m_tense][0] );
    // select a verb and display it in the lineedit
    m_verb = m_untrainedVerbs[ rand() % m_untrainedVerbs.size() ];
    bool spanish = ( KVerbosSettings::translatedVerbsF() ) ? false : true;
    spanish = ( KVerbosSettings::translatedVerbsA() ) ? ((rand() % 2) == 0) : spanish;
    spanish = (m_verb->translated()) ? spanish : true;
    editVerb->setReadOnly( spanish );
    editTranslation->setReadOnly( !spanish );
    if ( spanish ) {
        editVerb->setText( m_verb->infinitive() );
        if (m_verb->translated() ) {
            editTranslation->setEnabled( true );
            m_firstFocusWidget = editTranslation;
        } else {
            editTranslation->setEnabled( false );
            if (m_verb->reflexive()) {
                m_firstFocusWidget = m_formEdit[0][0];
            } else {
                m_firstFocusWidget = m_formEdit[1][0];
            }
        }
    } else {
        // <TODO> here the code if a translation should be used
        editTranslation->setEnabled( true );
        editTranslation->setText( "-- " + m_verb->infinitive() + " --" );
        m_firstFocusWidget = editVerb;
    }
    
    // now enable the necesary editlines
    for (int i = 0; i < 6; i++) {
        m_formEdit[0][i]->setEnabled( m_verb->reflexive() );
        m_formEdit[2][i]->setEnabled( Verbdata::TENSEINFO[m_tense][1] != "0" );
    }
    if ( m_tense == Verbdata::IMPERATIVO ) {
        m_formEdit[0][0]->setEnabled( false );
        m_formEdit[1][0]->setEnabled( false );
        m_firstFocusWidget = m_formEdit[1][1];
    }
    // probably m_formEdit[1][5] is always good to be the las focus widget.
    // I will test this. If it is alright m_lastFocusWidget could be deleted
    //m_lastFocusWidget = ( Verbdata::TENSEINFO[m_tense][1] == "0" ) ? m_formEdit[1][5] : m_formEdit[2][5];
    m_lastFocusWidget = m_formEdit[1][5];
    m_firstFocusWidget->setFocus( Qt::OtherFocusReason );
    m_mode = EXPECTING_INPUT;
    m_givenPoints = 0;
    m_solution = false;
    emit signalSetNextText( i18n("Correct Input") );
    return true;
}

bool FormsTrainer::prepareTenseList()
{
    m_tenses.clear();
    
    int simple = KVerbosSettings::simpleTenses();
    int composed = KVerbosSettings::composedTenses();
    int continuous = KVerbosSettings::continuousTenses();

    if ( KVerbosSettings::simpleTensesPresente() ) {
        addTense( 0, simple );
    }
    
    if ( KVerbosSettings::simpleTensesImperfecto() ) {
        addTense( 1, simple );
    }
    
    if ( KVerbosSettings::simpleTensesIndefinido() ) {
        addTense( 2, simple );
    }
    
    if ( KVerbosSettings::simpleTensesFuturo() ) {
        addTense( 3, simple );
    }
    
    if ( KVerbosSettings::simpleTensesCondicional() ) {
        addTense( 4, simple );
    }
    
    if ( KVerbosSettings::simpleTensesSubjuntivoPresente() ) {
        addTense( 5, simple );
    }
    
    if ( KVerbosSettings::simpleTensesSubjuntivoPasado() ) {
        addTense( 6, simple );
    }
    
    if ( KVerbosSettings::simpleTensesSubjuntivoFuturo() ) {
        addTense( 7, simple );
    }
    
    if ( KVerbosSettings::simpleTensesImperativo() ) {
        addTense( 8, simple );
    }
    
    if ( KVerbosSettings::perfectoTensesPresente() ) {
        addTense( 9, composed );
    }
    
    if ( KVerbosSettings::perfectoTensesImperfecto() ) {
        addTense( 10, composed );
    }
    
    if ( KVerbosSettings::perfectoTensesIndefinido() ) {
        addTense( 11, composed );
    }
    
    if ( KVerbosSettings::perfectoTensesFuturo() ) {
        addTense( 12, composed );
    }
    
    if ( KVerbosSettings::perfectoTensesCondicional() ) {
        addTense( 13, composed );
    }
    
    if ( KVerbosSettings::perfectoTensesSubjuntivoPresente() ) {
        addTense( 14, composed );
    }
    
    if ( KVerbosSettings::perfectoTensesSubjuntivoPasado() ) {
        addTense( 15, composed );
    }
    
    if ( KVerbosSettings::perfectoTensesSubjuntivoFuturo() ) {
        addTense( 16, composed );
    }
    
    if ( KVerbosSettings::progresivoTensesPresente() ) {
        addTense( 17, continuous );
    }
    
    if ( KVerbosSettings::progresivoTensesImperfecto() ) {
        addTense( 18, continuous );
    }
    
    if ( KVerbosSettings::progresivoTensesIndefinido() ) {
        addTense( 19, continuous );
    }
    
    if ( KVerbosSettings::progresivoTensesFuturo() ) {
        addTense( 20, continuous );
    }
    
    if ( KVerbosSettings::progresivoTensesCondicional() ) {
        addTense( 21, continuous );
    }
    return ( m_tenses.size() == 0 ) ? false : true;
}

void FormsTrainer::setVerbLists(QList<Verb*> untrained, QList<Verb*> trained)
{
    m_untrainedVerbs = untrained;
    m_trainedVerbs = trained;
}

void FormsTrainer::next()
{
    switch (m_mode) {
    case CORRECT_FORMS:
    case EXPECTING_INPUT: {
        // Correct the user input
        // Calculate how many points the task can give and how many are correct
        QVector<QString> forms = m_verb->conjugate();
        int points = 0;
        int correct = 0;
        // refelxiv pronouns possible 6 points
        if ( m_verb->reflexive() ) {
            points += 6;
            for ( int i = 0; i < 6; i++) {
                if (m_formEdit[0][i]->text() == Verb::REFLEXIV_PRONOUNS[i]) {
                    correct++;
                } else
                    m_formEdit[0][i]->setPalette( m_redPalette );
            }
        }
        // The infinitive or the translation possible 1 point
        if ( m_verb->translated() )
            kDebug() << "a translated verb can give one more point";

        // the particip or gerund form possible 1 point
        if ( Verbdata::TENSEINFO[m_tense][1] != "0" ) {
            points++;
            if ( Verbdata::TENSEINFO[m_tense][1] == "1" ) {
                // haber + partizip
                if ( ( m_formEdit[2][0]->text() == forms[61] ) || ( m_formEdit[2][0]->text() == forms[62] ) ) {
                    correct++;
                } else
                    m_formEdit[2][0]->setPalette( m_redPalette );
                forms = Verbdata::conjugate( "haber" );
            } else {
                // estar + gerund
                if ( m_formEdit[2][0]->text() == forms[60] ) {
                    correct++;
                } else
                    m_formEdit[2][0]->setPalette( m_redPalette );
                forms = Verbdata::conjugate( "estar" );
            }
        }

        // the forms or the forms of haber, estar possible 6 points or
        // if m_tense is IMPERATIVO 5 points
        points = ( m_tense == Verbdata::IMPERATIVO ) ? points + 5 : points + 6;
        int start = (Verbdata::TENSEINFO[m_tense][2]).toInt() * 6;
        int first = ( m_tense == Verbdata::IMPERATIVO ) ? 1 : 0;
        for (int i = first; i < 6; i++) {
            if ( ( m_formEdit[1][i]->text() == forms[start + i] ) ||
                 ( ( (m_tense == 6 ) || ( m_tense == 15 ) ) && ( m_formEdit[1][i]->text() == forms[start + 6 + i] ) ) ) {
                correct++;
            } else 
                m_formEdit[1][i]->setPalette( m_redPalette );
        }
        
        emit someExerciseSolved( (m_givenPoints == 0) ? points : correct - m_givenPoints,
                                  correct - m_givenPoints );
        m_givenPoints = correct;
        if ( points == correct ) {
            m_mode = SOLVED;
            m_lastFocusWidget->setFocus( Qt::OtherFocusReason );
            emit signalSetNextText( i18n("Next Task") );
        } else {
            m_mode = CORRECTED;
            m_firstFocusWidget->setFocus( Qt::OtherFocusReason );
            emit signalSetNextText( i18n("Show Solution") );
        }
        }
        break;
    case CORRECTED: {
        // The input is already corrected, the user wants to see the solution
        QVector<QString> forms = m_verb->conjugate();
        // refelxiv pronouns
        if ( m_verb->reflexive() ) {
            for ( int i = 0; i < 6; i++) {
                m_formEdit[0][i]->setText( Verb::REFLEXIV_PRONOUNS[i] );
            }
        }
        // The infinitive or the translation
        if ( m_verb->translated() )
            kDebug() << "set the right solution for infinitive or translation here";

        // the particip or gerund form
        if ( Verbdata::TENSEINFO[m_tense][1] != "0" ) {
            if ( Verbdata::TENSEINFO[m_tense][1] == "1" ) {
                // haber + partizip
                for (int i = 0; i < 6; i++) {
                    m_formEdit[2][i]->setText( forms[61] );
                }
                forms = Verbdata::conjugate( "haber" );
            } else {
                // estar + gerund
                for (int i = 0; i < 6; i++) {
                    m_formEdit[2][i]->setText( forms[60] );
                }
                forms = Verbdata::conjugate( "estar" );
            }
        }

        // the forms or the forms of haber, estar
        int start = (Verbdata::TENSEINFO[m_tense][2]).toInt() * 6;
        int first = ( m_tense == Verbdata::IMPERATIVO ) ? 1 : 0;
        for (int i = first; i < 6; i++) {
            // always show the first form. The alternative form isn't shown.
            m_formEdit[1][i]->setText( forms[start + i] );
        }
        m_lastFocusWidget->setFocus( Qt::OtherFocusReason );
        emit signalSetNextText( i18n("Next Task") );
        m_solution = true;
        m_mode = SOLVED;
        }
        break;
    case SOLVED:
        // if the user knew the correct answer m_verb is removed from the m_untrained list.
        if ( !m_solution ) {
            m_untrainedVerbs.removeAll( m_verb );
            m_trainedVerbs << m_verb;
            Verbdata::reportTraining( m_verb, false );
        } else 
            Verbdata::reportTraining( m_verb, true );
        //kDebug() << "untrained: " << m_untrainedVerbs.size() << " blocked: " << m_trainedVerbs.size();
        if ( m_untrainedVerbs.empty() || !setExercise() ) {
            emit allExercisesAreDone();
            //kDebug() << "All exercises are done";
        }
        break;
    default:
        kDebug() << "There is no mode like this: " << m_mode << endl;
    }
}

void FormsTrainer::slotChar(QString ch)
{
    QLineEdit* le = static_cast<QLineEdit*>( focusWidget() );
    if ( le ) {
        le->insert( ch );
    }
}

void FormsTrainer::slotDuplicate(QString text)
{
    for (int i = 0; i < 6; i++) {
        m_formEdit[2][i]->setText( text );
    }
}

void FormsTrainer::slotTextEdited(QString)
{
    if ( (m_mode = CORRECTED) || (m_mode = CORRECT_FORMS ) ) {
        m_mode = CORRECT_FORMS;
        emit signalSetNextText( i18n("Correct Input") );
        QLineEdit* le = static_cast<QLineEdit*>( focusWidget() );
        le->setPalette( m_oldPalette );
    }
}

void FormsTrainer::slotReturnPressed()
{
    QWidget* old = focusWidget();
    //kDebug() << old << " this was the widget.";
    if ( old == m_lastFocusWidget )
        next();
    else
        focusNextChild();
}

void FormsTrainer::addTense(int tense, int proportion)
{
    for (int i = 0; i < proportion; i++) {
        m_tenses << tense;
    }
}

void FormsTrainer::clearLineEdit()
{
    editVerb->setEnabled( true );
    editVerb->setReadOnly( false );
    editVerb->setText("");
    editTranslation->setEnabled( true );
    editTranslation->setReadOnly( false );
    editTranslation->setText("");
    for (int i = 0; i < 3; i++)
        for (int j = 0; j < 6; j++) {
            m_formEdit[i][j]->setEnabled( true );
            m_formEdit[i][j]->setReadOnly( false );
            m_formEdit[i][j]->setPalette( m_oldPalette );
            m_formEdit[i][j]->setText("");
        }
}



#include "formstrainer.moc"
