/* This file is part of the KDE project
   Copyright (C) 2000-2001 Bernd Gehrmann <bernd@kdevelop.org>
   Copyright (C) 2003 Alexander Dymo <cloudtemple@mksat.net>

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public
   License as published by the Free Software Foundation; either
   version 2 of the License, or (at your option) any later version.

   This library 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
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public License
   along with this library; see the file COPYING.LIB.  If not, write to
   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
   Boston, MA 02110-1301, USA.
*/
#include <tdelocale.h>
#include <kdebug.h>
#include <kurlrequester.h>
#include <klineedit.h>
#include <kdialogbase.h>
#include <tdeversion.h>

#include <tqapplication.h>
#include <tqtooltip.h>
#include <tqheader.h>
#include <tqstringlist.h>
#include <tqlayout.h>
#include <tqlabel.h>
#include <tqregexp.h>
#include <tqspinbox.h>

#include "flagboxes.h"

// partial copy of TQt-3.1 for back-compatibility to KDE-3.0
TQString TQRegExp_escape( const TQString& str )
{
    static const char meta[] = "$()*+.?[\\]^{|}";
    TQString quoted = str;
    int i = 0;

    while ( i < (int) quoted.length() ) {
	if ( strchr(meta, quoted[i].latin1()) != 0 )
	    quoted.insert( i++, "\\" );
	i++;
    }
    return quoted;
}


class FlagListToolTip : public TQToolTip
{
public:
    FlagListToolTip(TQWidget *parent);
protected:
    void maybeTip(const TQPoint &p);
};


FlagListToolTip::FlagListToolTip(TQWidget *parent)
    : TQToolTip(parent)
{}


void FlagListToolTip::maybeTip(const TQPoint &pos)
{
    FlagListBox *listbox = static_cast<FlagListBox*>(parentWidget());
    TQListViewItem *item = listbox->itemAt(pos);
    FlagListItem *flitem = static_cast<FlagListItem*>(item);

    if (item)
        tip(listbox->itemRect(item), flitem->desc);
}


FlagListItem::FlagListItem(FlagListBox *parent, const TQString &flagstr,
                           const TQString &description)
    : TQCheckListItem(parent, flagstr, TQCheckListItem::CheckBox),
      flag(flagstr), desc(description)
{}


FlagListItem::FlagListItem(FlagListBox *parent, const TQString &flagstr,
                           const TQString &description, const TQString &offstr)
    : TQCheckListItem(parent, flagstr, TQCheckListItem::CheckBox),
      flag(flagstr), off(offstr), desc(description)
{}


FlagListBox::FlagListBox(TQWidget *parent, const char *name)
    : TQListView(parent, name)
{
    setResizeMode(LastColumn);
    header()->hide();
    addColumn(i18n("Flags"));
    (void) new FlagListToolTip(this);
}


void FlagListBox::readFlags(TQStringList *list)
{
    TQListViewItem *item = firstChild();
    for (; item; item = item->nextSibling()) {
        FlagListItem *flitem = static_cast<FlagListItem*>(item);
        TQStringList::Iterator sli = list->find(flitem->flag);
        if (sli != list->end()) {
            flitem->setOn(true);
            list->remove(sli);
        }
        sli = list->find(flitem->off);
        if (sli != list->end()) {
            flitem->setOn(false);
            list->remove(sli);
        }
    }
}


void FlagListBox::writeFlags(TQStringList *list)
{
    TQListViewItem *item = firstChild();
    for (; item; item = item->nextSibling()) {
        FlagListItem *flitem = static_cast<FlagListItem*>(item);
        if (flitem->isOn())
            (*list) << flitem->flag;
    }
}


FlagCheckBox::FlagCheckBox(TQWidget *parent, FlagCheckBoxController *controller,
                           const TQString &flagstr, const TQString &description)
    : TQCheckBox(description, parent), flag(flagstr), includeOff(false), useDef(false), defSet(false)
{
    TQToolTip::add(this, flagstr);
    controller->addCheckBox(this);
}


FlagCheckBox::FlagCheckBox(TQWidget *parent, FlagCheckBoxController *controller,
                           const TQString &flagstr, const TQString &description,
                           const TQString &offstr)
    : TQCheckBox(description, parent), flag(flagstr), off(offstr), includeOff(false), useDef(false), defSet(false)
{
    TQToolTip::add(this, flagstr);
    controller->addCheckBox(this);
}

FlagCheckBox::FlagCheckBox(TQWidget *parent, FlagCheckBoxController *controller,
                           const TQString &flagstr, const TQString &description,
                           const TQString &offstr, const TQString &defstr)
    : TQCheckBox(description, parent), flag(flagstr), off(offstr), def(defstr), includeOff(false), useDef(true), defSet(false)
{
    TQToolTip::add(this, flagstr);
    controller->addCheckBox(this);
}

FlagCheckBoxController::FlagCheckBoxController(TQStringList multiKeys)
    :m_multiKeys(multiKeys)
{
}


void FlagCheckBoxController::addCheckBox(FlagCheckBox *item)
{
    cblist.append(item);
}


void FlagCheckBoxController::readFlags(TQStringList *list)
{
    //handle keys like -vxyz -> transform they into -vx -vy -vz
    //very "effective" algo :(
/*    TQStringList addons;
    for (TQStringList::Iterator mk = m_multiKeys.begin(); mk != m_multiKeys.end(); ++ mk)
    {
        kdDebug() << "multikey " << *mk << endl;
        for (TQStringList::Iterator sli = list->begin(); sli != list->end(); ++sli)
        {
            TQString key = *sli;
            kdDebug() << "current key: " << key << endl;
            if ( (key.length() > 3) && (key.startsWith(*mk)) )
            {
                list->remove(sli);
                key = key.remove(*mk);
                kdDebug() << "refined key " << key << endl;
                for (int i = 0; i < key.length(); ++i)
                {
                    kdDebug() << "adding key " << *mk + key[i] << endl;
                    addons << *mk + key[i];
                }
            }
        }
    }
    kdDebug() << "good" << endl;
    *list += addons;

    for (TQStringList::Iterator sli = list->begin(); sli != list->end(); ++sli)
    {
        kdDebug() << "KEYS: " << *sli << endl;
    }
*/
    TQPtrListIterator<FlagCheckBox> it(cblist);
    for (; it.current(); ++it) {
        FlagCheckBox *fitem = it.current();
        TQStringList::Iterator sli = list->find(fitem->flag);
        if (sli != list->end()) {
            fitem->setChecked(true);
            fitem->useDef = false;
            list->remove(sli);
        }
        sli = list->find(fitem->off);
        if (sli != list->end()) {
            fitem->setChecked(false);
            fitem->includeOff = true;
            fitem->useDef = false;
            list->remove(sli);
        }
        if (!fitem->def.isEmpty())
            if (fitem->useDef && (fitem->def == fitem->flag))
            {
                fitem->setChecked(true);
                fitem->defSet = true;
            }
        else
            fitem->useDef = false;
    }
}


void FlagCheckBoxController::writeFlags(TQStringList *list)
{
    TQPtrListIterator<FlagCheckBox> it(cblist);
    for (; it.current(); ++it) {
        FlagCheckBox *fitem = it.current();
        if (fitem->isChecked() && (!fitem->useDef))
        {
            (*list) << fitem->flag;
        }
        else if ((!fitem->off.isEmpty()) && fitem->includeOff)
            (*list) << fitem->off;
        else if ((fitem->def == fitem->flag) && (!fitem->isChecked()))
            (*list) << fitem->off;
        else if ((fitem->def == fitem->off) && (fitem->isChecked()))
            (*list) << fitem->flag;
    }
}

 FlagPathEditController::FlagPathEditController( )
{
}

 FlagPathEditController::~ FlagPathEditController( )
{
}

void FlagPathEditController::readFlags( TQStringList * list )
{
//    kdDebug() << "read path flags" << endl;
    TQPtrListIterator<FlagPathEdit> it(plist);
    for (; it.current(); ++it) {
        FlagPathEdit *peitem = it.current();

        TQStringList::Iterator sli = list->begin();
        while ( sli != list->end() )
        {
  //          kdDebug() << "option: " << (*sli) << " flag is: " << peitem->flag << endl;
            if ((*sli).startsWith(peitem->flag))
            {
//                kdDebug() << "Processing.." << endl;
                peitem->setText((*sli).replace(TQRegExp(TQRegExp_escape(peitem->flag)),""));
                sli = list->remove(sli);
                continue;
            }
             ++sli;
        }
/*        TQStringList::Iterator sli = list->find(peitem->flag);
        if (sli != list->end()) {
            peitem->setText((*sli).remove(peitem->flag));
            list->remove(sli);
        }*/
    }
}

void FlagPathEditController::writeFlags( TQStringList * list )
{
    TQPtrListIterator<FlagPathEdit> it(plist);
    for (; it.current(); ++it) {
        FlagPathEdit *pitem = it.current();
        if (!pitem->isEmpty())
            (*list) << pitem->flag + pitem->text();
    }
}

void FlagPathEditController::addPathEdit( FlagPathEdit * item )
{
    plist.append(item);
}

FlagPathEdit::FlagPathEdit( TQWidget * parent, TQString pathDelimiter,
    FlagPathEditController * controller, const TQString & flagstr, const TQString & description,
    KFile::Mode mode )
    : TQWidget(parent), delimiter(pathDelimiter), flag(flagstr), m_description(description)
{
    TQBoxLayout *topLayout = new TQVBoxLayout(this, 0, 1);
    topLayout->addWidget(new TQLabel(description, this));
    TQBoxLayout *layout = new TQHBoxLayout(topLayout, KDialog::spacingHint());

    if (delimiter.isEmpty())
    {
        url = new KURLRequester(this);
        url->setMode(mode);
        layout->addWidget(url);
    }
    else
    {
        edit = new KLineEdit(this);
        layout->addWidget(edit);
        details = new TQPushButton("...", this);
        details->setMaximumWidth(30);
        connect(details, TQT_SIGNAL(clicked()), this, TQT_SLOT(showPathDetails()));
        layout->addWidget(details);
    }

    TQApplication::sendPostedEvents(this, TQEvent::ChildInserted);

    TQToolTip::add(this, flagstr);
    controller->addPathEdit(this);
}

void FlagPathEdit::showPathDetails( )
{
    KDialogBase *dia = new KDialogBase(0, "flag_path_edit_dia", true, m_description,
        KDialogBase::Ok|KDialogBase::Cancel, KDialogBase::Ok, true);

    TQBoxLayout *diaLayout = new TQVBoxLayout(dia, KDialog::marginHint(), KDialog::spacingHint());
    diaLayout->setAutoAdd(true);

    KURLRequester *req = new KURLRequester( dia );
    req->setMode(KFile::Directory);
    KEditListBox::CustomEditor pCustomEditor;
    pCustomEditor = req->customEditor();
    KEditListBox *elb = new KEditListBox( "", pCustomEditor, dia );
    dia->setMainWidget(elb);

    elb->insertStringList(TQStringList::split(delimiter, text()));

    if (dia->exec() == TQDialog::Accepted)
    {
        setText(elb->items().join(delimiter));
    }

    delete dia;
}

void FlagPathEdit::setText( const TQString text )
{
    if (delimiter.isEmpty())
        url->setURL(text);
    else
        edit->setText(text);
}

TQString FlagPathEdit::text( )
{
    if (delimiter.isEmpty())
        return url->url();
    else
        return edit->text();
}

bool FlagPathEdit::isEmpty( )
{
    if (delimiter.isEmpty())
        return url->url().isEmpty();
    else
        return edit->text().isEmpty();
}

FlagRadioButton::FlagRadioButton( TQWidget * parent, FlagRadioButtonController * controller, const TQString & flagstr, const TQString & description )
    : TQRadioButton(description, parent), flag(flagstr)
{
    TQToolTip::add(this, flagstr);
    controller->addRadioButton(this);
}

FlagRadioButtonController::FlagRadioButtonController(TQStringList multiKeys)
    :m_multiKeys(multiKeys)
{
}

void FlagRadioButtonController::addRadioButton(FlagRadioButton *item)
{
    cblist.append(item);
}


void FlagRadioButtonController::readFlags(TQStringList *list)
{
    //handle keys like -vxyz -> transform they into -vx -vy -vz
    //very "effective" algo :(
/*    TQStringList addons;
    for (TQStringList::Iterator mk = m_multiKeys.begin(); mk != m_multiKeys.end(); ++ mk)
    {
        kdDebug() << "multikey " << *mk << endl;
        for (TQStringList::Iterator sli = list->begin(); sli != list->end(); ++sli)
        {
            TQString key = *sli;
            kdDebug() << "current key: " << key << endl;
            if ( (key.length() > 3) && (key.startsWith(*mk)) )
            {
                list->remove(sli);
                key = key.remove(*mk);
                kdDebug() << "refined key " << key << endl;
                for (int i = 0; i < key.length(); ++i)
                {
                    kdDebug() << "adding key " << *mk + key[i] << endl;
                    addons << *mk + key[i];
                }
            }
        }
    }
    kdDebug() << "good" << endl;
    *list += addons;

    for (TQStringList::Iterator sli = list->begin(); sli != list->end(); ++sli)
    {
        kdDebug() << "KEYS: " << *sli << endl;
    }
*/
    TQPtrListIterator<FlagRadioButton> it(cblist);
    for (; it.current(); ++it) {
        FlagRadioButton *fitem = it.current();
        TQStringList::Iterator sli = list->find(fitem->flag);
        if (sli != list->end()) {
            fitem->setChecked(true);
            list->remove(sli);
        }
    }
}


void FlagRadioButtonController::writeFlags(TQStringList *list)
{
    TQPtrListIterator<FlagRadioButton> it(cblist);
    for (; it.current(); ++it) {
        FlagRadioButton *fitem = it.current();
        if (fitem->isChecked())
            (*list) << fitem->flag;
    }
}

 FlagEditController::FlagEditController( )
{
}

 FlagEditController::~ FlagEditController( )
{
}

void FlagEditController::readFlags( TQStringList * list )
{
    TQPtrListIterator<FlagListEdit> it(plist);
    for (; it.current(); ++it) {
        FlagListEdit *peitem = it.current();

        TQStringList::Iterator sli = list->begin();
        while (sli != list->end())
        {
            if ((*sli).startsWith(peitem->flag))
            {
                peitem->appendText((*sli).replace(TQRegExp(TQRegExp_escape(peitem->flag)),""));
                sli = list->remove(sli);
                continue;
            }
            ++sli;
        }
    }


    TQPtrListIterator<FlagSpinEdit> it2(slist);
    for (; it2.current(); ++it2) {
        FlagSpinEdit *sitem = it2.current();

        TQStringList::Iterator sli = list->begin();
        while ( sli != list->end() )
        {
            if ((*sli).startsWith(sitem->flag))
            {
                sitem->setText((*sli).replace(TQRegExp(TQRegExp_escape(sitem->flag)),""));
                sli = list->remove(sli);
                continue;
            }
            ++sli;
        }
    }
}

void FlagEditController::writeFlags( TQStringList * list )
{
    TQPtrListIterator<FlagListEdit> it(plist);
    for (; it.current(); ++it) {
        FlagListEdit *pitem = it.current();
        if (!pitem->isEmpty())
            (*list) += pitem->flags();
    }

    TQPtrListIterator<FlagSpinEdit> it2(slist);
    for (; it2.current(); ++it2) {
        FlagSpinEdit *sitem = it2.current();
        if (!sitem->isDefault())
            (*list) << sitem->flags();
    }
}

void FlagEditController::addListEdit( FlagListEdit * item )
{
    plist.append(item);
}

void FlagEditController::addSpinBox(FlagSpinEdit *item)
{
    slist.append(item);
}


FlagListEdit::FlagListEdit( TQWidget * parent, TQString listDelimiter, FlagEditController * controller,
    const TQString & flagstr, const TQString & description)
    : TQWidget(parent), delimiter(listDelimiter), flag(flagstr), m_description(description)
{
    TQBoxLayout *topLayout = new TQVBoxLayout(this, 0, 1);
    topLayout->addWidget(new TQLabel(description, this));
    TQBoxLayout *layout = new TQHBoxLayout(topLayout, KDialog::spacingHint());

    edit = new KLineEdit(this);
    layout->addWidget(edit);
    if (! listDelimiter.isEmpty())
    {
        details = new TQPushButton("...", this);
        details->setMaximumWidth(30);
        connect(details, TQT_SIGNAL(clicked()), this, TQT_SLOT(showListDetails()));
        layout->addWidget(details);
    }

    TQApplication::sendPostedEvents(this, TQEvent::ChildInserted);

    TQToolTip::add(this, flagstr);
    controller->addListEdit(this);
}

void FlagListEdit::setText( const TQString text )
{
    edit->setText(text);
}

bool FlagListEdit::isEmpty( )
{
    return edit->text().isEmpty();
}

TQString FlagListEdit::text( )
{
    return edit->text();
}

void FlagListEdit::showListDetails( )
{
    KDialogBase *dia = new KDialogBase(0, "flag_list_edit_dia", true, m_description,
        KDialogBase::Ok|KDialogBase::Cancel, KDialogBase::Ok, true);

    TQBoxLayout *diaLayout = new TQVBoxLayout(dia, KDialog::marginHint(), KDialog::spacingHint());
    diaLayout->setAutoAdd(true);

    KEditListBox *elb = new KEditListBox( "", dia );
    dia->setMainWidget(elb);

    elb->insertStringList(TQStringList::split(delimiter, text()));

    if (dia->exec() == TQDialog::Accepted)
    {
        setText(elb->items().join(delimiter));
    }

    delete dia;
}

void FlagListEdit::appendText( const TQString text )
{
    edit->setText(edit->text() + (edit->text().isEmpty()?TQString(""):delimiter) + text);
}

TQStringList FlagListEdit::flags( )
{
    TQStringList fl = TQStringList::split(delimiter, text());
    for (TQStringList::iterator it = fl.begin(); it != fl.end(); ++it)
    {
        (*it).prepend(flag);
    }
    return fl;
}

FlagSpinEdit::FlagSpinEdit( TQWidget * parent, int minVal, int maxVal, int incr, int defaultVal, FlagEditController * controller, const TQString & flagstr, const TQString & description )
    :TQWidget(parent), m_defaultVal(defaultVal), flag(flagstr)
{
    TQBoxLayout *topLayout = new TQVBoxLayout(this, 0, 1);
    topLayout->addWidget(new TQLabel(description, this));

    spb = new TQSpinBox(minVal, maxVal, incr, this);
    spb->setValue(defaultVal);
    topLayout->addWidget(spb);

    TQApplication::sendPostedEvents(this, TQEvent::ChildInserted);

    TQToolTip::add(this, flagstr);
    controller->addSpinBox(this);
}

void FlagSpinEdit::setText( const TQString text )
{
    spb->setValue(text.toInt());
}

TQString FlagSpinEdit::text( )
{
    return TQString("%1").arg(spb->value());
}

TQString FlagSpinEdit::flags( )
{
    return flag + text();
}

bool FlagSpinEdit::isDefault( )
{
    if (spb->value() == m_defaultVal)
        return true;
    return false;
}


#include "flagboxes.moc"
