/*
  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.
*/

/*
  Copyright (C) 2005-2007 Peter Simonsson <psn@linux.se>
  Copyright (C) 2006 Dario Abatianni <eisfuchs@tigress.com>
  Copyright (C) 2006-2007 Eike Hein <hein@kde.org>
*/

#include "channeloptionsdialog.h"
#include "konversationapplication.h"
#include "channeloptionsui.h"
#include "channel.h"

#include <tqcheckbox.h>
#include <tqpushbutton.h>
#include <tqregexp.h>
#include <tqheader.h>
#include <tqtoolbutton.h>

#include <tdelocale.h>
#include <tdelistview.h>
#include <ktextedit.h>
#include <klineedit.h>
#include <knuminput.h>
#include <tdelistviewsearchline.h>
#include <kiconloader.h>


namespace Konversation
{

    ChannelOptionsDialog::ChannelOptionsDialog(Channel *channel)
        : KDialogBase(channel, "channelOptions", false, i18n("Channel Settings for %1").arg(channel->getName()), Ok|Cancel, Ok)
    {
        Q_ASSERT(channel);
        m_widget = new ChannelOptionsUI(this);
        setMainWidget(m_widget);

        m_widget->otherModesList->setRenameable(0, false);
        m_widget->otherModesList->setRenameable(1, true);
        m_widget->otherModesList->hide();

        // don't allow sorting. most recent topic is always first
        m_widget->topicHistoryList->setSortColumn(-1);
        m_widget->clearButton->setIconSet(SmallIconSet("locationbar_erase"));
        m_widget->banList->setDefaultRenameAction(TQListView::Accept);
        m_widget->banListSearchLine->setListView(m_widget->banList);
        // hide column where the complete topic will be put in for convenience
        m_widget->topicHistoryList->hideColumn(2);
        // do not allow the user to resize the hidden column back into view
        m_widget->topicHistoryList->header()->setResizeEnabled(false,2);

        m_channel = channel;
        m_editingTopic = false;

        connect(m_widget->topicHistoryList, TQ_SIGNAL(clicked(TQListViewItem*)), this, TQ_SLOT(topicHistoryItemClicked(TQListViewItem*)));
        connect(m_widget->topicHistoryList, TQ_SIGNAL(selectionChanged(TQListViewItem*)), this, TQ_SLOT(topicHistoryItemClicked(TQListViewItem*)));
        connect(m_widget->toggleAdvancedModes, TQ_SIGNAL(clicked()), this, TQ_SLOT(toggleAdvancedModes()));
        connect(m_widget->topicEdit, TQ_SIGNAL(modificationChanged(bool)), this, TQ_SLOT(topicBeingEdited(bool)));

        connect(m_channel, TQ_SIGNAL(topicHistoryChanged()), this, TQ_SLOT(refreshTopicHistory()));

        connect(m_channel, TQ_SIGNAL(modesChanged()), this, TQ_SLOT(refreshModes()));
        connect(m_channel->getOwnChannelNick(), TQ_SIGNAL(channelNickChanged()), this, TQ_SLOT(refreshEnableModes()));

        connect(this, TQ_SIGNAL(cancelClicked()), this, TQ_SLOT(cancelClicked()));
        connect(this, TQ_SIGNAL(okClicked()), this, TQ_SLOT(changeOptions()));
        connect(this, TQ_SIGNAL(okClicked()), this, TQ_SLOT(okClicked()));

        connect(m_channel, TQ_SIGNAL(banAdded(const TQString&)), this, TQ_SLOT(addBan(const TQString&)));
        connect(m_channel, TQ_SIGNAL(banRemoved(const TQString&)), this, TQ_SLOT(removeBan(const TQString&)));
        connect(m_channel, TQ_SIGNAL(banListCleared()), m_widget->banList, TQ_SLOT(clear()));

        connect(m_widget->addBan, TQ_SIGNAL(clicked()), this, TQ_SLOT(addBanClicked()));
        connect(m_widget->removeBan, TQ_SIGNAL(clicked()), this, TQ_SLOT(removeBanClicked()));
        connect(m_widget->banList, TQ_SIGNAL(itemRenamed (TQListViewItem*)), this, TQ_SLOT(banEdited(TQListViewItem*)));
        connect(m_widget->banList, TQ_SIGNAL(itemRenamed (TQListViewItem*, int, const TQString&)), this, TQ_SLOT(banEdited(TQListViewItem*)));

        refreshTopicHistory();
        refreshBanList();
        refreshAllowedChannelModes();
        refreshModes();
    }

    ChannelOptionsDialog::~ChannelOptionsDialog()
    {
    }

    void ChannelOptionsDialog::changeOptions()
    {
        TQString newTopic = topic(), oldTopic=m_channel->getTopicHistory().first().section(' ', 2);

        if(newTopic != oldTopic)
        {
            // Pass a ^A so we can determine if we want to clear the channel topic.
            if (newTopic.isEmpty())
            {
                if (!oldTopic.isEmpty())
                    m_channel->sendChannelText(Preferences::commandChar() + "TOPIC " + m_channel->getName() + " \x01");
            }
            else
                m_channel->sendChannelText(Preferences::commandChar() + "TOPIC " + m_channel->getName() + ' ' + newTopic);
        }

        TQStringList newModeList = modes();
        TQStringList currentModeList = m_channel->getModeList();
        TQStringList rmModes;
        TQStringList addModes;
        TQStringList tmp;
        TQString modeString;
        bool plus;
        TQString command("MODE %1 %2%3 %4");

        for(TQStringList::iterator it = newModeList.begin(); it != newModeList.end(); ++it)
        {
            modeString = (*it).mid(1);
            plus = ((*it)[0] == '+');
            tmp = currentModeList.grep(TQRegExp('^' + modeString));

            if(tmp.isEmpty() && plus)
            {
                m_channel->getServer()->queue(command.arg(m_channel->getName()).arg("+").arg(modeString[0]).arg(modeString.mid(1)));
            }
            else if(!tmp.isEmpty() && !plus)
            {
                //FIXME: Bahamuth requires the key parameter for -k, but ircd breaks on -l with limit number.
                //Hence two versions of this.
                if (modeString[0] == 'k')
                    m_channel->getServer()->queue(command.arg(m_channel->getName()).arg("-").arg(modeString[0]).arg(modeString.mid(1)));
                else
                    m_channel->getServer()->queue(command.arg(m_channel->getName()).arg("-").arg(modeString[0]).arg(""));
            }
        }
        hide();
    }

    void ChannelOptionsDialog::toggleAdvancedModes()
    {
        bool ison = m_widget->toggleAdvancedModes->isOn();
        m_widget->otherModesList->setShown(ison);
        if(ison)
        {
            m_widget->toggleAdvancedModes->setText(i18n("&Hide Advanced Modes <<"));
        }
        else
        {
            m_widget->toggleAdvancedModes->setText(i18n("&Show Advanced Modes >>"));
        }
    }

    void ChannelOptionsDialog::topicBeingEdited(bool state)
    {
        m_editingTopic = state;
    }

    TQString ChannelOptionsDialog::topic()
    {
        return m_widget->topicEdit->text().replace("\n"," ");
    }

    void ChannelOptionsDialog::refreshTopicHistory()
    {
        TQStringList history = m_channel->getTopicHistory();
        m_widget->topicHistoryList->clear();

        for(TQStringList::const_iterator it = history.fromLast(); it != history.end(); --it)
        {
            TQDateTime date;
            date.setTime_t((*it).section(' ', 0 ,0).toUInt());
            new TDEListViewItem(m_widget->topicHistoryList, (*it).section(' ', 1, 1), date.toString(TQt::LocalDate), (*it).section(' ', 2));
        }

        // update topic preview
        topicHistoryItemClicked(m_widget->topicHistoryList->selectedItem());
        // don't destroy the user's edit box if they started editing
        if(!m_editingTopic)
            m_widget->topicEdit->setText(history.first().section(' ', 2));
    }

    void ChannelOptionsDialog::topicHistoryItemClicked(TQListViewItem* item)
    {
        // if they didn't click on anything, item is null
        if(item)
            // update topic preview
            m_widget->topicPreview->setText(item->text(2));
        else
            // clear topic preview
            m_widget->topicPreview->setText("");
    }

    void ChannelOptionsDialog::refreshEnableModes()
    {
        bool enable = m_channel->getOwnChannelNick()->isAnyTypeOfOp();
        m_widget->otherModesList->setEnabled(enable);
        m_widget->topicEdit->setReadOnly(!enable && m_widget->topicModeChBox->isChecked());

        m_widget->topicModeChBox->setEnabled(enable);
        m_widget->messageModeChBox->setEnabled(enable);
        m_widget->userLimitChBox->setEnabled(enable);
        m_widget->userLimitEdit->setEnabled(enable);
        m_widget->inviteModeChBox->setEnabled(enable);
        m_widget->moderatedModeChBox->setEnabled(enable);
        m_widget->secretModeChBox->setEnabled(enable);
        m_widget->keyModeChBox->setEnabled(enable);
        m_widget->keyModeEdit->setEnabled(enable);

        m_widget->banList->setItemsRenameable(enable);
        m_widget->addBan->setEnabled(enable);
        m_widget->removeBan->setEnabled(enable);
    }

    void ChannelOptionsDialog::refreshAllowedChannelModes()
    {
        TQString modeString = m_channel->getServer()->allowedChannelModes();
        // These modes are handled in a special way: ntimslkbeI
        modeString.remove('t');
        modeString.remove('n');
        modeString.remove('l');
        modeString.remove('i');
        modeString.remove('m');
        modeString.remove('s');
        modeString.remove('k');
        modeString.remove('b');
        modeString.remove('e');
        modeString.remove('I');
        modeString.remove('O');
        modeString.remove('o');
        modeString.remove('v');

        for(unsigned int i = 0; i < modeString.length(); i++)
        {
            new TQCheckListItem(m_widget->otherModesList, TQString(modeString[i]), TQCheckListItem::CheckBox);
        }
    }

    void ChannelOptionsDialog::refreshModes()
    {
        TQStringList modes = m_channel->getModeList();

        m_widget->topicModeChBox->setChecked(false);
        m_widget->messageModeChBox->setChecked(false);
        m_widget->userLimitChBox->setChecked(false);
        m_widget->userLimitEdit->setValue(0);
        m_widget->inviteModeChBox->setChecked(false);
        m_widget->moderatedModeChBox->setChecked(false);
        m_widget->secretModeChBox->setChecked(false);
        m_widget->keyModeChBox->setChecked(false);
        m_widget->keyModeEdit->setText("");

        TQListViewItem* item = m_widget->otherModesList->firstChild();

        while(item)
        {
            static_cast<TQCheckListItem*>(item)->setOn(false);
            item = item->nextSibling();
        }

        char mode;

        for(TQStringList::const_iterator it = modes.begin(); it != modes.end(); ++it)
        {
            mode = (*it)[0];

            switch(mode)
            {
                case 't':
                    m_widget->topicModeChBox->setChecked(true);
                    break;
                case 'n':
                    m_widget->messageModeChBox->setChecked(true);
                    break;
                case 'l':
                    m_widget->userLimitChBox->setChecked(true);
                    m_widget->userLimitEdit->setValue((*it).mid(1).toInt());
                    break;
                case 'i':
                    m_widget->inviteModeChBox->setChecked(true);
                    break;
                case 'm':
                    m_widget->moderatedModeChBox->setChecked(true);
                    break;
                case 's':
                    m_widget->secretModeChBox->setChecked(true);
                    break;
                case 'k':
                    m_widget->keyModeChBox->setChecked(true);
                    m_widget->keyModeEdit->setText((*it).mid(1));
                    break;
                default:
                {
                    bool found = false;
                    item = m_widget->otherModesList->firstChild();
                    TQString modeString;
                    modeString = mode;

                    while(item && !found)
                    {
                        if(item->text(0) == modeString)
                        {
                            found = true;
                            static_cast<TQCheckListItem*>(item)->setOn(true);
                            item->setText(1, (*it).mid(1));
                        }
                        else
                        {
                            item = item->nextSibling();
                        }
                    }

                    break;
                }
            }
        }

        refreshEnableModes();
    }

    TQStringList ChannelOptionsDialog::modes()
    {
        TQStringList modes;
        TQString mode;

        mode = (m_widget->topicModeChBox->isChecked() ? "+" : "-");
        mode += 't';
        modes.append(mode);
        mode = (m_widget->messageModeChBox->isChecked() ? "+" : "-");
        mode += 'n';
        modes.append(mode);
        mode = (m_widget->userLimitChBox->isChecked() ? "+" : "-");
        mode += 'l' + TQString::number( m_widget->userLimitEdit->value() );
        modes.append(mode);
        mode = (m_widget->inviteModeChBox->isChecked() ? "+" : "-");
        mode += 'i';
        modes.append(mode);
        mode = (m_widget->moderatedModeChBox->isChecked() ? "+" : "-");
        mode += 'm';
        modes.append(mode);
        mode = (m_widget->secretModeChBox->isChecked() ? "+" : "-");
        mode += 's';
        modes.append(mode);

        if (m_widget->keyModeChBox->isChecked() && !m_widget->keyModeEdit->text().isEmpty())
        {
            mode = '+';
            mode += 'k' + m_widget->keyModeEdit->text();
            modes.append(mode);
        }
        else if (!m_widget->keyModeChBox->isChecked())
        {
            mode = '-';
            mode += 'k' + m_widget->keyModeEdit->text();
            modes.append(mode);
        }

        TQListViewItem* item = m_widget->otherModesList->firstChild();

        while(item)
        {
            mode = (static_cast<TQCheckListItem*>(item)->isOn() ? "+" : "-");
            mode += item->text(0) + item->text(1);
            modes.append(mode);
            item = item->nextSibling();
        }

        return modes;
    }

    // Ban List tab related functions

    void ChannelOptionsDialog::refreshBanList()
    {
        TQStringList banlist = m_channel->getBanList();
        m_widget->banList->clear();

        for (TQStringList::const_iterator it = banlist.fromLast(); it != banlist.end(); --it)
            addBan((*it));
    }

    void ChannelOptionsDialog::addBan(const TQString& newban)
    {
        new BanListViewItem(m_widget->banList, newban.section(' ', 0, 0), newban.section(' ', 1, 1).section('!', 0, 0), newban.section(' ', 2 ,2).toUInt());
    }

    void ChannelOptionsDialog::removeBan(const TQString& ban)
    {
        delete m_widget->banList->findItem(ban, 0);
    }

    void ChannelOptionsDialog::banEdited(TQListViewItem *edited)
    {
        if (edited == m_NewBan)
        {
            if (!m_NewBan->text(0).isEmpty())
            {
                m_channel->getServer()->requestBan(TQStringList(m_NewBan->text(0)), m_channel->getName(), TQString());
            }

            // We will delete the item and let the addBan slot handle
            // readding the item because for some odd reason using
            // startRename causes further attempts to rename the item
            // using 2 mouse clicks to fail in odd ways.
            delete edited;

            return;
        }

        BanListViewItem *new_edited = dynamic_cast <BanListViewItem*> (edited);
        if (new_edited == NULL) return; // Should not happen.

        if (new_edited->getOldValue() != new_edited->text(0))
        {
            m_channel->getServer()->requestUnban(new_edited->getOldValue(), m_channel->getName());

            if (!new_edited->text(0).isEmpty())
            {
                m_channel->getServer()->requestBan(TQStringList(new_edited->text(0)), m_channel->getName(), TQString());
            }

            // We delete the existing item because it's possible the server may
            // Modify the ban causing us not to catch it. If that happens we'll be
            // stuck with a stale item and a new item with the modified hostmask.
            delete new_edited;
        }
    }

    void ChannelOptionsDialog::addBanClicked()
    {
        m_NewBan = new BanListViewItem(m_widget->banList, true);

        m_NewBan->setRenameEnabled(0,true);
        m_NewBan->startRename(0);
    }

    void ChannelOptionsDialog::removeBanClicked()
    {
        if (m_widget->banList->currentItem())
            m_channel->getServer()->requestUnban(m_widget->banList->currentItem()->text(0), m_channel->getName());
    }

    void ChannelOptionsDialog::cancelClicked()
    {
        if (m_widget->banList->renameLineEdit()->isShown())
        {
            TQKeyEvent e(TQEvent::KeyPress, TQt::Key_Escape, 27, TQt::NoButton);

            TDEApplication::sendEvent(m_widget->banList->renameLineEdit(), &e);
        }

        topicBeingEdited(false);
        hide();
    }

    void ChannelOptionsDialog::okClicked()
    {
        if (m_widget->banList->renameLineEdit()->isShown())
        {
            TQKeyEvent e(TQEvent::KeyPress, TQt::Key_Return, 13, TQt::NoButton);

            TDEApplication::sendEvent(m_widget->banList->renameLineEdit(), &e);
        }
    }

    // This is our implementation of BanListViewItem

    BanListViewItem::BanListViewItem(TQListView *parent)
      : TDEListViewItem(parent)
    {
        m_isNewBan = 0;
    }

    BanListViewItem::BanListViewItem(TQListView *parent, bool isNew)
      : TDEListViewItem(parent)
    {
        m_isNewBan = isNew;
    }

    BanListViewItem::BanListViewItem (TQListView *parent, const TQString& label1, const TQString& label2,
        uint timestamp) : TDEListViewItem(parent, label1, label2)
    {
        m_isNewBan = 0;
        m_timestamp.setTime_t(timestamp);
    }

    BanListViewItem::BanListViewItem (TQListView *parent, bool isNew, const TQString& label1, const TQString& label2,
        uint timestamp) : TDEListViewItem(parent, label1, label2)
    {
        m_isNewBan = isNew;
        m_timestamp.setTime_t(timestamp);
    }

    TQString BanListViewItem::text(int column) const
    {
        if (column == 2)
            return TDEGlobal::locale()->formatDateTime(m_timestamp, true, true);

        return TDEListViewItem::text(column);
    }

    int BanListViewItem::compare(TQListViewItem *i, int col, bool ascending) const
    {
        if (col == 2)
        {
            BanListViewItem* item = static_cast<BanListViewItem*>(i);

            if (m_timestamp == item->timestamp())
                return 0;
            else if (m_timestamp < item->timestamp())
                return -1;
            else
                return 1;
        }

        return TDEListViewItem::compare(i, col, ascending);
    }

    void BanListViewItem::startRename( int col )
    {
        m_oldValue = text(col);

        TDEListViewItem::startRename(col);
    }

    void BanListViewItem::cancelRename( int col )
    {
        if (text(col).isEmpty() && m_isNewBan)
            delete this;
        else
            TDEListViewItem::cancelRename(col);
    }
}

#include "channeloptionsdialog.moc"
