/***************************************************************************
                         kpercentmain.cpp  -  description
                            -------------------
   begin                : Fri Nov 16 2001
  copyright            : (C) 2001 by Matthias Messmer <bmlmessmer@web.de> &
                                     Carsten Niehaus <cniehaus@gmx.de> &
                                     Robert Gogolok <mail@robert-gogolok.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.                                   *
 *                                                                         *
 ***************************************************************************/

#include "kpercentmain.h"

// C/C++ includes
#include <stdlib.h>
#include <time.h>

// Qt includes
#include <QApplication>
#include <QPainter>
#include <QLabel>
#include <QProgressBar>
#include <QPushButton>
#include <QPixmap>
#include <QTimerEvent>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QKeyEvent>
#include <QLineEdit>

// KDE includes
#include <KGuiItem>
#include <KIconLoader>
#include <KLocale>
#include <KStandardDirs>
#include <KStandardGuiItem>
#include <KIntValidator>
#include <KSvgRenderer>

// local includes
#include "kpercentage.h"

KPercentMain::KPercentMain( QWidget *parent, const char *name ) : KDialog( parent )
{
    setCaption( "KPercentage" );
    setButtons(0);
    setFont( parent->font() );
    /** load and set the background pixmap */
    //QPixmap bgp( KStandardDirs::locate( "data", QApplication::isRightToLeft() ? "kpercentage/pics/kpercentmain_bg_rtl.png" : "kpercentage/pics/kpercentmain_bg.png" ) );

    QString backgroundSvgPath = KStandardDirs::locate("data",
					    QApplication::isRightToLeft()  ? QString("kpercentage/pics/kpercentage_bg_rtl.svgz") : QString( "kpercentage/pics/kpercentage_bg.svgz" ) );

    m_renderer = new KSvgRenderer();
    m_renderer->load( backgroundSvgPath );
    m_backgroundCache = QPixmap();
    //resize( 520, 220 );
    //setFixedSize( QSize( 520, 275 ) );

    QPalette palette;
    //palette.setBrush( backgroundRole(), QBrush(bgp) );
    setPalette( palette );

    KIntValidator *validLine = new KIntValidator( this );

    line_edit_percentage = new QLineEdit( this );
    line_edit_percentage->setAlignment(  Qt::AlignHCenter  );
    line_edit_percentage->setValidator( validLine );

    line_edit_basevalue = new QLineEdit( this );
    line_edit_basevalue->setAlignment(  Qt::AlignHCenter  );
    line_edit_basevalue->setValidator( validLine );

    line_edit_percentvalue = new QLineEdit( this );
    line_edit_percentvalue->setAlignment(  Qt::AlignHCenter  );
    line_edit_percentvalue->setValidator( validLine );

    progress_bar_count = new QProgressBar( this );
    //progress_bar_count->setFixedWidth( 250 );

    progress_bar_right_wrong = new QProgressBar( this );
    //progress_bar_right_wrong->setFixedWidth( 250 );
    progress_bar_right_wrong->setTextVisible( false );

    QPalette progressPalette;
    progressPalette.setColor( progress_bar_right_wrong->backgroundRole(), Qt::red );
    progress_bar_right_wrong->setPalette( progressPalette );

    label_right = new QLabel( this );
    label_right->setPalette( palette );
    label_wrong = new QLabel( this );
    label_wrong->setPalette( palette );

    push_button_apply = new QPushButton( this );
    push_button_apply->setText( KStandardGuiItem::apply().text() );
    push_button_apply->setDefault( true );
    push_button_apply->setPalette( palette );

    push_button_cancel = new QPushButton( this );
    push_button_cancel->setText( KStandardGuiItem::cancel().text() );

    KIconLoader icon_loader;
    push_button_apply->setIcon( QIcon( icon_loader.loadIcon( "dialog-ok", KIconLoader::NoGroup, 32 ) ) );
    push_button_cancel->setIcon( QIcon( icon_loader.loadIcon( "dialog-cancel", KIconLoader::NoGroup, 32 ) ) );

    label_1 = new QLabel( this );
    // xgettext: no-c-format
    label_1->setText( i18n( " % of " ) );
    label_1->setPalette( palette );

    label_2 = new QLabel( this );
    label_2->setText( i18n( " = " ) );
    label_2->setPalette( palette );

    label_number = new QLabel( this );
    label_number->setObjectName( "label_number" );
    label_number->setPalette( palette );
    label_number->setText( i18n( "Task no. MM:" ) ); // for the right width

    label_count = new QLabel( this );
    label_count->setObjectName( "label_count" );
    label_count->setText( i18n( "You got MM of MM." ) ); // for the right width
    label_count->setPalette( palette );

    //////
    // begin layouting
    //////
    delete layout();
    QVBoxLayout *main_layout = new QVBoxLayout ( this );
    main_layout->setObjectName( "main_layout" );
    main_layout->setMargin( 20 );
    main_layout->setSpacing( 10 );

    QHBoxLayout *label_number_layout = new QHBoxLayout ();
    main_layout->addItem(label_number_layout);
    label_number_layout->setObjectName( "label_number_layout" );
    label_number_layout->addWidget( label_number );
    label_number_layout->addStretch();

    QHBoxLayout *line_edit_layout = new QHBoxLayout ( );
    main_layout->addItem( line_edit_layout );
    main_layout->setObjectName( "line_edit_layout" );
    line_edit_layout->addWidget( line_edit_percentage );
    line_edit_layout->addWidget( label_1 );
    line_edit_layout->addWidget( line_edit_basevalue );
    line_edit_layout->addWidget( label_2 );
    line_edit_layout->addWidget( line_edit_percentvalue );
    line_edit_layout->addStretch();

    main_layout->addStretch();

    QHBoxLayout *bottom_layout = new QHBoxLayout(  );
    main_layout->addItem( bottom_layout );
    bottom_layout->setObjectName( "bottom_layout" );

    QVBoxLayout *current_state_layout = new QVBoxLayout (  );
    current_state_layout->setSpacing( 6 );
    bottom_layout->addItem( current_state_layout );
    current_state_layout->setObjectName( "current_state_layout" );

    QHBoxLayout *label_count_layout = new QHBoxLayout (  );
    current_state_layout->addItem( label_count_layout );
    label_count_layout->setObjectName( "label_count_layout" );
    label_count_layout->addWidget( label_count );
    label_count_layout->addStretch();

    current_state_layout->addSpacing( 10 );
    current_state_layout->addWidget( progress_bar_count );

    QHBoxLayout *right_wrong_layout = new QHBoxLayout( );
    right_wrong_layout->setSpacing( 6 );
    current_state_layout->addItem( right_wrong_layout );
    right_wrong_layout->setObjectName( "right_wrong_layout" );

    right_wrong_layout->addWidget( label_right );
    right_wrong_layout->addWidget( progress_bar_right_wrong );
    right_wrong_layout->addWidget( label_wrong );

    bottom_layout->addSpacing( 40 );

    QVBoxLayout *button_layout = new QVBoxLayout ( );
    bottom_layout ->addItem( button_layout );
    button_layout->setObjectName( "button_layout" );

    button_layout->addWidget( push_button_apply );
    button_layout->addSpacing( 10 );
    button_layout->addWidget( push_button_cancel );

    // END LAYOUT
    // --------------------------------------------------------

    // tab order
    setTabOrder( line_edit_percentvalue, push_button_apply );
    setTabOrder( push_button_apply, push_button_cancel );

    ///////////
    // ToolTips

    progress_bar_count->setToolTip( i18n( "Number of managed exercises" ) );
    progress_bar_right_wrong->setToolTip( i18n( "Relation of right to wrong inputs" ) );
    push_button_apply->setToolTip( i18n( "Check your answer" ) );
    push_button_cancel->setToolTip( i18n( "Back to the main window" ) );

    // signals and slots connections
    connect( push_button_apply, SIGNAL( clicked() ), this, SLOT( slotApplyInput() ) );
    connect( push_button_cancel, SIGNAL( clicked() ), this, SLOT( accept() ) );

    // build up the answer window
    answer = new KAnswer( this );

    /** this is to tell rand() to be randomizing */
    srandom( time( 0 ) );
}

KPercentMain::~KPercentMain()
{
    delete m_renderer;
}

void KPercentMain::paintEvent( QPaintEvent * e )
{
    QPainter p(this);
    paintBackground(p, e->rect());
}

void KPercentMain::paintBackground(QPainter &p, const QRect& rect)
{
    // Draw the background
    if (m_backgroundCache.size() != size()) {
        m_backgroundCache = QPixmap(size());
        QPainter aux(&m_backgroundCache);
        m_renderer->render(&aux);
    }
     p.drawPixmap(rect.topLeft(), m_backgroundCache, rect);
}

/** No descriptions */
void KPercentMain::newTask()
{
    // no Editline can be focused
    line_edit_percentage->setFocusPolicy( Qt::NoFocus );
    line_edit_basevalue->setFocusPolicy( Qt::NoFocus );
    line_edit_percentvalue->setFocusPolicy( Qt::NoFocus );

    // set the number of managed tasks into a label
    label_count->setText( QString( i18n("You got %1 of %2 exercises.", count, number) ) ); // update Label for the Progress

    // progress_bar_count->setProgress( count*100 ); // updating Progrssbar
    startTimer( 10 );
    // set string which task is just workin on (Task x of y)
    QString taskNumber( i18n( "Exercise no. %1:" , count+1) );

    label_number->setText( taskNumber );
    //    label_number->adjustSize();

    int selection; // which task is to be solved ?
     if ( count == number )  // all tasks managed ?
     {
        // finished();
     }
    else
    {
        if ( selected_type == SEL_RANDOM )
        {
            selection = rand() % 3;  // select one task by random
        }
        else
        {
            selection = selected_type; // or take the preselected one
        }
        // set the right line_edit_layout for input
        switch ( selection )
        {
        case SEL_PERCENTAGE:
            line_edit_input = line_edit_percentage;
            break;
        case SEL_BASEVALUE:
            line_edit_input = line_edit_basevalue;
            break;
        case SEL_PERCENTVALUE:
            line_edit_input = line_edit_percentvalue;
            break;
        }
        // show the numbers
        showNumbers();
        // delete this one
        line_edit_input->clear();
        // make the line_edit_layout accessable
        line_edit_input->setFocusPolicy( Qt::StrongFocus );
        // set the focus on it
        line_edit_input->setFocus();
    }
}

/** checks, if the task is solved right */
bool KPercentMain::validateTask()
{
    // here is some mathematics :)
    return ( getPercentage() * getBasevalue() == 100 * getPercentvalue() );
}

/** gets the numbers from the line_edit_layouts */
int KPercentMain::getPercentage()
{
    return line_edit_percentage->text().toInt(); // check for valid input is omitted (slotApplyInput)
}
int KPercentMain::getBasevalue()
{
    return line_edit_basevalue->text().toInt(); // check for valid input is omitted (slotApplyInput)
}
int KPercentMain::getPercentvalue()
{
    return line_edit_percentvalue->text().toInt(); // check for valid input is omitted (slotApplyInput)
}

/* checks, if the input is a val. number
 * calls validateTask then and if succeeds causes a newTask */
void KPercentMain::slotApplyInput()
{
    bool ok; // conversion to int successful ?
    line_edit_input->text().toInt( &ok );
    if ( !ok )
    {
        showAnswer( 3 );
    }
    else
    {
        if ( validateTask() )  // are the numbers right ?
        {
            showAnswer( 1 );
            count++; // one more solved
            right_answers++; // one more right answer
            total_answers++;
            progress_bar_right_wrong->setRange( 0, total_answers );
            progress_bar_right_wrong->setValue( right_answers );
            label_right->setText( i18n( "%1%\nright", (100*right_answers)/total_answers ) );
            label_wrong->setText( i18n( "%1%\nwrong", 100-(100*right_answers)/total_answers ) );

            newTask(); // next task, perhaps
        }
        else
        {
            showAnswer( 2 );
            wrong_answers++; // one more right answer
            total_answers++;
            progress_bar_right_wrong->setRange( 0, total_answers );
            progress_bar_right_wrong->setValue( right_answers );
            label_right->setText( i18n( "%1%\nright", (100*right_answers)/total_answers ) );
            label_wrong->setText( i18n( "%1%\nwrong", 100-(100*right_answers)/total_answers ) );
        }

        label_right->show();
        label_wrong->show();
    }
}

/** inserts the numbers of a new task in the line_edit_layouts */
void KPercentMain::showNumbers()
{
    line_edit_percentage->setText( QString::number( percentage[ count ] ) );
    line_edit_basevalue->setText( QString::number( basevalue[ count ] ) );
    line_edit_percentvalue->setText( QString::number( percentvalue[ count ] ) );
}

/** called, if number tasks are managed */
void KPercentMain::finished()
{
    showAnswer( 4 );
    accept(); // hides the dialog
}
/** shows the kanswer dialog modal with an proper answer about the success. */
void KPercentMain::showAnswer( int modus )
{
    answer->setAnswer( modus );
    answer->exec();
}
/** sets the total amount of tasks selekted in opening screen */
void KPercentMain::setNumber( int anumber )
{
    number = anumber;
    progress_bar_count->setRange( 0, number*100 );
}

/** Prepares the exercise of number tasks */
void KPercentMain::initExercise()
{
    count = 0;
    progress_bar_count->setValue( 0 );
    total_answers = 0;
    right_answers = 0;
    wrong_answers = 0;

    progress_bar_right_wrong->setValue( 0 );
    label_right->setText( "" );
    label_right->hide();
    label_wrong->setText( "" );
    label_wrong->hide();
    switch ( selected_level )
    {
        /** easy level */
    case 0:
        {
            /** easy percentages to calculate with */
            const int values[] = { 1, 10, 25, 50, 75, 100, 10, 25, 50, 75};
            ::memcpy(percentage, values, sizeof(values));
        }


        int num;
        if ( number < 6 )    /* for only few tasks, chose from the first 6 numbers */
        {
            num = 6;
        }
        else
        {
            num = 10;     /* else take them all! */
        }
        /** swap 20 times in the array */
        for ( int i = 0; i < 20; i++ )
        {
            int m = rand() % num;
            int n = rand() % num;
            if ( n == m )  /* not a swap */
            {
                n = ( n + 1 ) % num;
            }
            int h = percentage[ m ];
            percentage[ m ] = percentage[ n ];
            percentage[ n ] = h;
        }
        for ( int i = 0; i < number; i++ )
        {
            /** basevalue 100..2000 by chance */
            basevalue[ i ] = 100 * ( 1 + rand() % 20 );
            /** calc percentvalue */
            percentvalue[ i ] = percentage[ i ] * basevalue[ i ] / 100;
        }
        break;
    case 1:
        {
            /** some more tricky percentages */
            const int values[] = { 0, 5, 10, 20, 60, 90, 100, 110, 150, 200};
            ::memcpy(percentage, values, sizeof(values));
        }
        /** swap some times in this array */
        for ( int i = 0; i < 20; i++ )
        {
            int m = rand() % 10;
            int n = rand() % 10;
            if ( n == m )  /** not a swap */
            {
                n = ( n + 1 ) % 10;
            }
            int h = percentage[ m ];
            percentage[ m ] = percentage[ n ];
            percentage[ n ] = h;
        }
        for ( int i = 0; i < number; i++ )
        {
            /** basevalue 0..2000 */
            basevalue[ i ] = 100 * ( rand() % 21 );
            /** calc percentvalue */
            percentvalue[ i ] = percentage[ i ] * basevalue[ i ] / 100;
        }
        break;
    case 2:
        int factor;
        for ( int i = 0; i < number; i++ )
        {
            /** this lines give you 3 integer by chance. percentage will be somewhere
              * between 0 and 200. We use factorisation to have "almost" random numbers
              * and _always_ valid numbers. */
            factor = 1;
            if ( rand() % 2 == 1 )
                factor *= 2;
            if ( rand() % 2 == 1 )
                factor *= 2;
            if ( rand() % 2 == 1 )
                factor *= 5;
            if ( rand() % 2 == 1 )
                factor *= 5;
            percentage[ i ] = rand() % ( 200 / factor );
            basevalue[ i ] = rand() % ( 10 * factor );
            percentvalue[ i ] = percentage[ i ] * basevalue[ i ];
            percentage[ i ] *= factor;
            basevalue[ i ] *= 100 / factor;
        }
        break;
    }
    newTask(); /** prepare the window for the first task */
}

void KPercentMain::timerEvent( QTimerEvent *event )
{
    if( progress_bar_count->value()<count*100 )
    {
      progress_bar_count->setValue(progress_bar_count->value()+1);
    }
    else
    {
        killTimer( event->timerId() );
    }

    if( progress_bar_count->value()==number*100 )
        finished();
}

void KPercentMain::keyPressEvent( QKeyEvent * e )
{
    if ( e->key() == Qt::Key_Enter )
        slotApplyInput();
    else
        KDialog::keyPressEvent( e );
}

#include "kpercentmain.moc"
