/***************************************************************************
 *   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 "verbselection.h"


// Qt header files
#include <QGridLayout>
#include <QHBoxLayout>
#include <QSpacerItem>
#include <QLabel>
#include <QCheckBox>
#include <QRadioButton>
#include <QSpinBox>
#include <QTreeWidget>
#include <QTreeWidgetItem>
#include <QStringList>
#include <QDate>
#include <QProgressBar>

#include <QTableWidgetItem>

// KDE header files
#include <kdebug.h>
#include <kconfig.h>
#include <klocale.h>
#include <kstandarddirs.h>
#include <kconfigdialog.h>
#include <kmessagebox.h>
#include <ktreewidgetsearchline.h>
//#include <kpushbutton.h>

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

// --------------------------------------------------------------------------
//
// class MyTreeWidgetItem
//
// --------------------------------------------------------------------------

MyTreeWidgetItem::MyTreeWidgetItem (MappingInfo* map, QTreeWidgetItem* parent, const QStringList& strings, int type)
    : QTreeWidgetItem(parent, strings, type), m_mappingInfo(map)
{
}

MyTreeWidgetItem::MyTreeWidgetItem (MappingInfo* map, QTreeWidget* parent, const QStringList& strings, int type)
    : QTreeWidgetItem(parent, strings, type), m_mappingInfo(map)
{
}

MyTreeWidgetItem::~MyTreeWidgetItem()
{
}





// --------------------------------------------------------------------------
//
// class MyTabWidget
//
// --------------------------------------------------------------------------

MyTabWidget::MyTabWidget (QWidget* parent)
    : QTabWidget(parent)
{
    m_parent = (VerbSelection*)parent;
}

MyTabWidget::~MyTabWidget()
{
}

QStringList MyTabWidget::verblist()
{
    QStringList l;
    for (QList<Verb*>::iterator it = m_selection.begin(); it < m_selection.end(); it++) {
        l << ((*it)->infinitive() + "=" + QString::number((*it)->level()) + "=" + QString::number((*it)->lastDay()));
    }
    return l;
}

void MyTabWidget::setVerblist(QStringList verbselection)
{
    m_parent->blockTreeSignals(true);
    QStringList texts;
    for (QStringList::iterator it = verbselection.begin(); it < verbselection.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 {
            m_selection << verb;
            verb->setStatus( true, parts.at(1).toInt(), parts.at(2).toInt() );
            QString days;
            int julianDate = verb->lastDay();
            if (julianDate == Verb::FOREVER) {
                days = "---";
            } else {
                QDate today = QDate::currentDate();
                days = QString::number(julianDate - today.toJulianDay());
            }
            texts.clear();
            texts << parts.at(0) << Verb::LEVELNAMES[(parts.at(1)).toInt()] << days;
            m_parent->selectedTree->addTopLevelItem(new QTreeWidgetItem(texts));
            
            // find a mapping info and adapt the item in the other treewidgets
            MappingInfo* map = m_parent->findMap(verb);
            if (map == 0) {
                kDebug() << "Didn't find MappingInfo for the Verb " << verb->infinitive() << endl;
            } else {
                map->grammarItem->setCheckState(0, Qt::Checked);
                map->alphabetItem->setCheckState(0, Qt::Checked);
                map->alphabetItem->setText(1, Verb::LEVELNAMES[map->verb->level()]);
                map->alphabetItem->setText(2, days);
                map->grammarItem->setText(1, Verb::LEVELNAMES[map->verb->level()]);
                map->grammarItem->setText(2, days);
            }
        }
    }
    
    // check if the parentElements in the other treewidget have the correct status
    m_parent->checkAllParentItems();
    
    m_parent->selectedTree->sortItems(0, Qt::AscendingOrder);
    m_parent->blockTreeSignals(false);
}

void MyTabWidget::handleVerb(MappingInfo* map, bool add)
{
    if (add) {
        if (m_selection.contains(map->verb))
            return;
        m_selection.append(map->verb);
        map->verb->setSelected(true);
        QStringList texts;
        texts << map->verb->infinitive() << Verb::LEVELNAMES[map->verb->level()] << "---";
        MyTreeWidgetItem* item = new MyTreeWidgetItem(map, m_parent->selectedTree, texts, VerbSelection::VerbType);
        map->selectedItem = item;
        item->setMappingInfo(map);
        m_parent->selectedTree->addTopLevelItem(item);
        //m_parent->selectedTree->sortItems(0, Qt::AscendingOrder);
        map->alphabetItem->setText(1, Verb::LEVELNAMES[map->verb->level()]);
        map->alphabetItem->setText(2, "---");
        map->grammarItem->setText(1, Verb::LEVELNAMES[map->verb->level()]);
        map->grammarItem->setText(2, "---");
    } else {
        if (!m_selection.contains(map->verb))
            return;
        map->verb->setSelected(false);
        m_selection.removeAll(map->verb);
        m_parent->selectedTree->takeTopLevelItem(m_parent->selectedTree->indexOfTopLevelItem(map->selectedItem));
        map->selectedItem = 0;
        map->alphabetItem->setText(1, "");
        map->alphabetItem->setText(2, "");
        map->grammarItem->setText(1, "");
        map->grammarItem->setText(2, "");
    }
}



// --------------------------------------------------------------------------
//
// class VerbSelection
//
// --------------------------------------------------------------------------

const int VerbSelection::ParentTypeAlphabet = 1001;
const int VerbSelection::ParentTypeGrammar = 1002;
const int VerbSelection::ChildType  = 1003;
const int VerbSelection::VerbType   = 1004;

VerbSelection::VerbSelection(QWidget *parent) 
    : QWidget(parent)
{
    m_parent = (KConfigDialog*)parent;
    if ( objectName().isEmpty() )
        setObjectName( QString::fromUtf8("VerbSelection") );

    QList<int> searchColumns;
    searchColumns << 0;
    KTreeWidgetSearchLine* searchLine = 0;
    QHBoxLayout* hBox = 0;
    // All the GUI elements
    QSize size( 560, 300 );
    setMinimumSize( size );
    resize( size );
    // The tabwidget for the three tabs
    gridLayout = new QGridLayout( this );
    kcfg_verbselection = new MyTabWidget( this );
    kcfg_verbselection->setObjectName( QString::fromUtf8("kcfg_verbselection") );
    // The tab for all the already selected verbs
    selected = new QWidget( kcfg_verbselection );
    gridLayout1 = new QGridLayout( selected );
    selectedTree = new QTreeWidget( selected );
    gridLayout1->addWidget( selectedTree, 0, 0, 1, 1 );
    hBox = new QHBoxLayout();
    hBox->addWidget( new QLabel( i18n("Look for an infinitive") ) );
    searchLine = new KTreeWidgetSearchLine( this, selectedTree );
    searchLine->setSearchColumns(searchColumns);
    hBox->addWidget( searchLine );
    gridLayout1->addLayout( hBox, 1, 0, 1, 1);
    kcfg_verbselection->addTab(selected, i18n("List of Selected Verbs"));
    adjustColumnWidth(selectedTree);
    // The tab for all verbs ordered in grammatical groups
    grammar = new QWidget();
    gridLayout3 = new QGridLayout(grammar);
    grammarTree = new QTreeWidget(grammar);
    gridLayout3->addWidget(grammarTree, 0, 0, 1, 1);
    hBox = new QHBoxLayout();
    hBox->addWidget( new QLabel( i18n("Look for an infinitive")));
    searchLine = new KTreeWidgetSearchLine(this, grammarTree);
    searchLine->setSearchColumns(searchColumns);
    hBox->addWidget( searchLine );
    gridLayout3->addLayout(hBox, 1, 0, 1, 1);
    kcfg_verbselection->addTab(grammar, i18n("Verbs in Grammatical Groups"));
    adjustColumnWidth(grammarTree);
    // The tab for all verbs in alphabetical order
    alphabet = new QWidget();
    gridLayout2 = new QGridLayout(alphabet);
    alphabetTree = new QTreeWidget(alphabet);
    gridLayout2->addWidget(alphabetTree, 0, 0, 1, 1);
    hBox = new QHBoxLayout();
    hBox->addWidget( new QLabel( i18n("Look for an infinitive")));
    searchLine = new KTreeWidgetSearchLine(this, alphabetTree);
    searchLine->setSearchColumns(searchColumns);
    hBox->addWidget( searchLine );
    gridLayout2->addLayout( hBox, 1, 0, 1, 1 );
    kcfg_verbselection->addTab(alphabet, i18n("Verbs in Alphabetical Groups"));
    adjustColumnWidth(alphabetTree);

    gridLayout->addWidget( kcfg_verbselection, 0, 0, 1, 1);
    kcfg_verbselection->setCurrentIndex(0);
    
    // I think the two buttons aren't necessary. If they are delete the comment
    // a button to select all verbs and a button to deselect all verbs
    //QHBoxLayout* box2 = new QHBoxLayout();
    //selectAll = new KPushButton(i18n("select all"), this);
    //dropAll = new KPushButton(i18n("drop all"), this);
    //box2->addWidget(selectAll);
    //box2->addWidget(dropAll);
    //box2->addItem(new QSpacerItem(61, 26, QSizePolicy::Expanding, QSizePolicy::Minimum));
    //gridLayout->addLayout(box2, 1, 0, 1, 1);
    
    // write the verbs into the tabs, alphabetical and grammar order.
    QStringList texts;
    texts << i18n("Categories & Verbs") << i18n("Level") << i18n("Time to stay");
    alphabetTree->setHeaderLabels(texts);
    grammarTree->setHeaderLabels(texts);
    texts.replace( 0, i18n("Selected Verbs") );
    selectedTree->setHeaderLabels(texts);
    texts.clear();
    texts << "" << "" << "";
    for (char ch = 'A'; ch <= 'Z'; ch++) {
        texts.replace(0, i18n("First letter is ") + ch);
        m_alphabetItem[ch - 'A'] = new QTreeWidgetItem(alphabetTree, texts, VerbSelection::ParentTypeAlphabet);
        m_alphabetItem[ch - 'A']->setCheckState(0, Qt::Unchecked);
    }
    for (int i = 0; i < Verbdata::GROUPS; i++) {
        texts.replace(0, Verbdata::GROUPNAMES[i]);
        m_grammarItem[i] = new QTreeWidgetItem(grammarTree, texts, VerbSelection::ParentTypeGrammar);
        m_grammarItem[i]->setCheckState(0, Qt::Unchecked);
    }
    if (!m_map.isEmpty())
        kDebug() << "The List with the MappingInfos isn't empty. But it should be." << endl;
    QList<Verb*>* verbs = Verbdata::getVerblist();
    for (QList<Verb*>::iterator it = verbs->begin(); it < verbs->end(); it++) {
        MappingInfo* m = new MappingInfo;
        m->verb = *it;
        
        QString infinitive = m->verb->infinitive();
        texts.replace(0, infinitive);
        int n = infinitive.at(0).toUpper().toAscii() - 'A';
        n = ((n < 0) || (n > 26)) ? 25 : n;
        m->alphabetItem = new MyTreeWidgetItem(m, m_alphabetItem[n], texts, VerbSelection::ChildType);
        m->alphabetItem->setCheckState(0, Qt::Unchecked);
        
        int g = Verbdata::GROUPMATCH[m->verb->family()];
        m->grammarItem = new MyTreeWidgetItem(m, m_grammarItem[g], texts, VerbSelection::ChildType);
        m->grammarItem->setCheckState(0, Qt::Unchecked);
        
        m->selectedItem = 0;
        m_map.append(m);
    }
    connect(alphabetTree, SIGNAL(itemChanged(QTreeWidgetItem*, int)), this, SLOT(itemChanged(QTreeWidgetItem*, int)));
    connect(grammarTree, SIGNAL(itemChanged(QTreeWidgetItem*, int)), this, SLOT(itemChanged(QTreeWidgetItem*, int)));
}

// The MappingInfos aren't a QObject class. So delete them.
VerbSelection::~VerbSelection()
{
    if (!m_map.isEmpty()) {
        for (QList<MappingInfo*>::iterator it = m_map.begin(); it < m_map.end(); it++) {
            MappingInfo* m = *it;
            delete m;
        }
        m_map.clear();
    }
}

void VerbSelection::blockTreeSignals(bool block)
{
    grammarTree->blockSignals(block);
    alphabetTree->blockSignals(block);
    selectedTree->blockSignals(block);
}

MappingInfo* VerbSelection::findMap(Verb* verb)
{
    MappingInfo* r = 0;
    for (QList<MappingInfo*>::iterator it = m_map.begin(); it < m_map.end(); it++) {
        if ((*it)->verb == verb) {
            r = *it;
            break;
        }
    }
    return r;
}

void VerbSelection::checkAllParentItems()
{
    findAllCheckState(m_grammarItem, Verbdata::GROUPS);
    findAllCheckState(m_alphabetItem, 26);
}

void VerbSelection::adjustColumnWidth(QTreeWidget* w)
{
    w->setColumnWidth(0, 300);
    w->setColumnWidth(1, 80);
    w->setColumnWidth(2, 80);
}

void VerbSelection::changeItem(QTreeWidgetItem* item)
{
    blockTreeSignals(true);

    Qt::CheckState state = item->checkState(0);
    
    if (item->type() == VerbSelection::ChildType) {
        MyTreeWidgetItem* myItem = dynamic_cast<MyTreeWidgetItem*>(item);
        if (myItem != 0) {
            MappingInfo* map = myItem->mappingInfo();
            ((MyTabWidget*)kcfg_verbselection)->handleVerb(map, state == Qt::Checked);
            selectedTree->sortItems(0, Qt::AscendingOrder);
            MyTreeWidgetItem* partner = (map->alphabetItem == myItem) ? map->grammarItem : map->alphabetItem;
            // set the check-state of the partner to the same state
            if (state != partner->checkState(0)) {
                partner->setCheckState(0, state);
                findCheckState(partner->parent());
            }
            // set the check state of the parent
            findCheckState(item->parent());
        } else {
            kDebug() << "myItem is null. That's atrange." << endl;
        }
    } else {
        // all the children and their partners get the same check state as the item
        // this may take some time especially for the -ar verbs.
        if (state == Qt::PartiallyChecked) {
            kDebug() << "The element should be checked or unchecked but not partially checked. This is strange." << endl;
        } else {
            kDebug() << "select start";
            int n = item->childCount();
            for (int i = 0; i < n; i++) {
                item->child(i)->setCheckState(0, state);
                MyTreeWidgetItem* myItem = dynamic_cast<MyTreeWidgetItem*>(item->child(i));
                if (myItem == 0) 
                    kDebug() << "The myItem pointer is null. How can it happen?" << endl;
                else {
                    MappingInfo* map = myItem->mappingInfo();
                    MyTreeWidgetItem* partner = (map->alphabetItem == myItem) ? map->grammarItem : map->alphabetItem;
                    partner->setCheckState(0, state);
                    ((MyTabWidget*)kcfg_verbselection)->handleVerb(map, state == Qt::Checked);
                }
            }
            // now adjust the parents of all the partner items.
            if (item->type() == VerbSelection::ParentTypeAlphabet) {
                findAllCheckState(m_grammarItem, Verbdata::GROUPS);
            } else {
                findAllCheckState(m_alphabetItem, 26);
            }
            selectedTree->sortItems(0, Qt::AscendingOrder);
            kDebug() << "select stop";
        }
    }
    blockTreeSignals(false);
}

void VerbSelection::findAllCheckState(QTreeWidgetItem* a[], int n)
{
    for (int i = 0; i < n; i++) {
        findCheckState( a[i] );
    }
}

void VerbSelection::findCheckState(QTreeWidgetItem* item)
{
    Qt::CheckState state = Qt::Unchecked;
    int n = item->childCount();
    if (n > 0) {
        state = item->child(0)->checkState(0);
        for (int j = 1; j < n; j++) {
            if (item->child (j)->checkState(0) != state) {
                state = Qt::PartiallyChecked;
                break;
            }
        }
    }
    item->setCheckState(0, state);
}

void VerbSelection::itemChanged(QTreeWidgetItem* current, int column)
{
    if (0 == column) {
        changeItem(current);
        m_parent->enableButtonApply(true);
    }
}

#include "verbselection.moc"
