/* -*- C++ -*-

Copyright (C) 2000-2002 Francesco Bresciani <fbresciani@users.sourceforge.net>
This file is part of Kemistry

Kemistry 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, or (at your option)
any later version.

Kemistry 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 Kemistry; see the file COPYING.  If not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

*/


#include <typeinfo>

#include <qcheckbox.h>
#include <qdict.h>
#include <qgroupbox.h>
#include <qlabel.h>
#include <qlineedit.h>
#include <qlistbox.h>
#include <qstring.h>
#include <qvalidator.h>

#include <kdebug.h>
#include <klocale.h>
#include <kmessagebox.h>

#include "kmolcalcparser.h"
#include "kmolcalceditor.h"


KMolCalcEditor::KMolCalcEditor(QWidget* parent) : KMolCalcEditorBase(parent)
{
	QDoubleValidator *validator = new QDoubleValidator(_editMass);
	_parser = new KMolCalcParser;
	validator->setRange(0.0, 1000000.0, 6);
	_editMass->setValidator(validator);
	fillListBox();
}

void KMolCalcEditor::slotRemove()
{
        
	// remove an item (atom, group) from KMolCalcParser dictionary
	// // only user defined items can be removed!
    QString currentItem = _listboxData->currentText();
	if (currentItem.isNull())
		return;
    if (currentItem.right(1) == "*")
        currentItem = currentItem.left(currentItem.length() -1);

    const KMolCalcSubUnit* subUnit = KMolCalcData::pointer()->
		data(currentItem);
    if (!subUnit)
        return;
    if (!subUnit->userDefined())
    {
        KMessageBox::sorry(this, i18n("Only user defined elements or"
					" groups can be deleted"));
		return;
	}
        
	else
    {
		KMolCalcData::pointer()->removeSubUnit(currentItem);
		KMolCalcData::pointer()->setModified(true);
        fillListBox();
        }

    }

void KMolCalcEditor::slotApplyChanges()
{
    // check if no lineedits are empty
    if (_editSymbol->text().isEmpty())
    {
        KMessageBox::sorry(this, i18n("'Symbol' line edit is empty"));
        return;
    }

    if (_editName->text().isEmpty())
    {
        KMessageBox::sorry(this, i18n("'Name' line edit is empty"));
        return;
    }

    if (_groupAtom->isEnabled())
        if (_editMass->text().isEmpty())
        {
            KMessageBox::sorry(this, i18n("'Mass' line edit is empty"));
            return;
        }

    if (_groupGroup->isEnabled())
        if (_editFormula->text().isEmpty())
        {
            KMessageBox::sorry(this, i18n("'Formula' line edit is empty"));
            return;
        }

    // Check if symbol begins with an uppercase character //
	// and contains only lower case characters
    QString symbol = _editSymbol->text();
    bool onlyLower = true;
    for (uint i = 1; i < symbol.length(); i++)
        if (symbol[i].category() != QChar::Letter_Lowercase)
            onlyLower = false;
    if (!(symbol[0].category() == QChar::Letter_Uppercase && onlyLower))
        {
            KMessageBox::sorry(this,
                               i18n("Symbol must begin with an uppercase "
								   "character and the remaining characters "
								   "must be lowercase!"));
            return;
        }


        //Is this a new item?
        if (_editNew)
        {
            // The user wants to create a new Item. 
			// Check if an item in the dictionary
            // has the same symbol proposed by the user.
            // If true, ask the user if he wants to replace 
			// //the item in the dictionary.
            // If false, add this item to the dictionary
            if (KMolCalcData::pointer()->data(_editSymbol->text()))
                if (!overwriteItem(_editSymbol->text()))
                    return;
        }

        //add or modify data in the dictionary
        if (_groupAtom->isEnabled())
        {
            KMolCalcElement* element =
                new KMolCalcElement(_editName->text(),
                                            _editSymbol->text(),
                                            _editMass->text().toFloat());

            element->setUserDefined(true);
            KMolCalcData::pointer()->addSubUnit(element->symbol(), element);
            fillListBox();
            return;
        }

        if (_groupGroup->isEnabled())
        {
            QString parsedFormula = _parser->
				parseFormulaToString(_editFormula->text());
            QString errormsg = _parser->errorMessage();
            if (errormsg == QString::null)
            {
                KMolCalcGroup* group =
                    new KMolCalcGroup(_editName->text(), _editSymbol->text(),
							_editFormula->text(), parsedFormula);

                group->setUserDefined(true);
                KMolCalcData::pointer()->addSubUnit(group->symbol(), group);
                fillListBox();
                return;
            }
            else
            {
                KMessageBox::error(this, i18n("Error while parsing formula: ") +
                                   errormsg);
                return;
            }
        }
    }


    bool KMolCalcEditor::overwriteItem(const QString& symbol)
    {
        QString message =
            i18n("The symbol '%1' is already used\n"
                 "Do you want to replace it?\n"
                 "The original item may be restored deleting the "
                 "new one (which appears in the listbox with an asterisk)").arg(symbol) ;

        return (KMessageBox::warningYesNo(this, message)==KMessageBox::Yes);
    }

    void KMolCalcEditor::slotNewAtom()
    {
        _groupProperties->setEnabled(true);
        _groupGroup->setEnabled(false);
        _groupAtom->setEnabled(true);

        _editSymbol->clear();
        _editName->clear();
        _editMass->clear();

        _editNew = true;
    }


    void KMolCalcEditor::slotNewGroup()
    {
        _groupProperties->setEnabled(true);
        _groupGroup->setEnabled(true);
        _groupAtom->setEnabled(false);

        _editSymbol->clear();
        _editName->clear();
        _editFormula->clear();

        _editNew = true;
    }

    void KMolCalcEditor::slotItemSelected(const QString& symbol)
    {
        QString symb;
        if (symbol.right(1) == "*")
            symb = symbol.left(symbol.length()-1);
        else
            symb = symbol;
        KMolCalcSubUnit* subUnit =
            KMolCalcData::pointer()->data(symb);
        if (!subUnit)
            return;

        // is this subunit an atom?
        KMolCalcElement *element = dynamic_cast<KMolCalcElement*>(subUnit);
        if (element)
        {
            _groupProperties->setEnabled(true);
            _groupAtom->setEnabled(true);
            _groupGroup->setEnabled(false);

            _editSymbol->setText(element->symbol());
            _editName->setText(element->name());
            _editMass->setText(QString::number(element->mass()));

            _editNew = false;
            _symbolEdited = element->symbol();
            return;
        }

        // is this subunit a group?
        const KMolCalcGroup *group = dynamic_cast<const KMolCalcGroup*>(subUnit);
        if (group)
        {
            _groupProperties->setEnabled(true);
            _groupAtom->setEnabled(false);
            _groupGroup->setEnabled(true);

            _editSymbol->setText(group->symbol());
            _editName->setText(group->name());
            _editFormula->setText(group->formula());

            _editNew = false;
            _symbolEdited = group->symbol();
            return;
        }

        // we shouldn't go here!!!
        // we have find an unknown subunit!
        kdWarning() << "KMolCalcEditor::slotItemHighlighted() : "
                    <<"Unknown subunit found in subunits dictionary!"<<endl;

    }

    void KMolCalcEditor::fillListBox()
    {
        QString itemText;

        _listboxData->clear();
        uint atomsCount = 0;
        uint groupsCount = 0;
        uint redefinedAtomsCount = 0;
        uint redefinedGroupsCount = 0;
        bool textInList = false;
        QStringList symbols;

        QDictIterator<KMolCalcSubUnit> it(KMolCalcData::pointer()->dataDictionary());
        while (it.current())
        {
            itemText = it.current()->symbol();
            textInList = (symbols.find(it.current()->symbol()) != symbols.end()) ||
                         (symbols.find(it.current()->symbol()+"*") != symbols.end());

            if (dynamic_cast<KMolCalcElement*>(it.current()))
            {
                atomsCount++;
                if (textInList)
                    redefinedAtomsCount++;
            }
            else
                if (dynamic_cast<KMolCalcGroup*>(it.current()))
                {
                    groupsCount++;
                    if (textInList)
                        redefinedGroupsCount++;
                }

            if (it.current()->userDefined())
                itemText += "*";
            symbols.append(itemText);
            ++it;
        }
        _listboxData->clear();
        _listboxData->insertStringList(symbols);

        _labelAtomsCount->setText(i18n("Defined elements: %1").arg(atomsCount));
        _labelGroupsCount->setText(i18n("Defined groups: %1").arg(groupsCount));
        _labelRedefinedAtomsCount->setText(i18n("(redefined elements: %1)")
                                           .arg(redefinedAtomsCount));
        _labelRedefinedGroupsCount->setText(i18n("(redefined groups: %1)")
                                            .arg(redefinedGroupsCount));
        _listboxData->sort();
    }


    KMolCalcEditorDlg::KMolCalcEditorDlg(QWidget* parent) :
        KDialogBase(parent, "mmcalc_editor_dialog", false, i18n("Elements and groups editor"),
                    Close|Help, Close, true)
    {
        KMolCalcEditor* editor = new KMolCalcEditor(this);
        setMainWidget(editor);
}

#include "kmolcalceditor.moc"
