/*
 *
 * Copyright (C) 2002 George Staikos <staikos@kde.org>
 * Copyright (C) 2002 Rich Moore <rich@kde.org>
 *               2004 Dirk Ziegelmeier <dziegel@gmx.de>
 *
 * 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 Steet, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */

#include <qobject.h>
#include <qcheckbox.h>
#include <qlcdnumber.h>
#include <qlabel.h>
#include <qlineedit.h>
#include <qcombobox.h>

#include <klocale.h>
#include <kdebug.h>
#include <kpushbutton.h>
#include <knuminput.h>
#include <kapplication.h>
#include <kiconloader.h>
#include <kpopupmenu.h>

#include "channel.h"
#include "channelstore.h"
#include "channelpropertiesdialogimpl.h"
#include "sourcemanager.h"
#include "channeleditor.h"
#include "channeleditor.moc"


#define CLI_RTTI 589425

int ChannelListItem::rtti() const
{
    return CLI_RTTI;
}


ChannelListItem::ChannelListItem(KListView* parent, Channel* ch, bool sso)
    : KListViewItem(parent, QString::number(ch->number()), ch->name()),
      c(ch), _showSelectedOnly(sso)
{
    if ( (!c->enabled()) && (_showSelectedOnly) )
        setVisible(false);

    connect(c, SIGNAL(changed()), this, SLOT(updateFields()));
}


ChannelListItem::~ChannelListItem()
{
}


void ChannelListItem::updateFields()
{
    if ( (!c->enabled()) && (_showSelectedOnly) )
        setVisible(false);
    else
        setVisible(true);

    if (c->name() != text(1))
        setText(1, c->name());

    if (QString::number(c->number()) != text(0))
        setText(0, QString::number(c->number()));
}


int ChannelListItem::compare(QListViewItem *i, int col, bool ascending) const
{
    int me, him;

    if (i->rtti() != CLI_RTTI)
        return KListViewItem::compare(i, col, ascending);

    switch (col) {
    case 0:
        me = c->number();
        him = static_cast<ChannelListItem*>(i)->c->number();

        if (me == him) return 0;

        return (ascending ? 1 : -1) * (me > him ? 1 : -1);
        break;
    default:
        break;
    }

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


ChannelEditor::ChannelEditor( QWidget *parent, SourceManager* srcm, const char *name, bool showSelectedOnly )
    : KListView( parent, name ? name : "channel_editor" ),
      cs(0),
      _srcm(srcm),
      _showSelectedOnly(showSelectedOnly),
      prev(0)
{
    addColumn( "", -10 );
    addColumn( i18n("Name") );

    setResizeMode( LastColumn );
    setAllColumnsShowFocus( true );
    setColumnAlignment( 0, AlignCenter );
    setColumnAlignment( 1, AlignLeft );

    setItemsRenameable( true );
    setRenameable( 0, false );
    setRenameable( 1, true );

    _pop = new KPopupMenu(this, "ChannelEditorPopup");
    _titleId = _pop->insertTitle(i18n("Channel"));
    _hpId    = _pop->insertItem(KGlobal::iconLoader()->loadIcon("konqueror",
                                                                KIcon::NoGroup,
                                                                KIcon::SizeSmall),
                                i18n("Open Homepage"), this, SLOT( browseItem() ));
    _pop->insertItem(KGlobal::iconLoader()->loadIcon("edit",
                                                    KIcon::NoGroup,
                                                    KIcon::SizeSmall),
                     i18n("Edit..."), this, SLOT( editItem() ));

    connect( this, SIGNAL( itemRenamed(QListViewItem *, const QString &, int) ),
             this, SLOT( renameItem(QListViewItem *, const QString &, int) ) );
    connect( this, SIGNAL( selectionChanged(QListViewItem*) ),
             this, SLOT( requestChange(QListViewItem*) ) );
    connect( this, SIGNAL( doubleClicked(QListViewItem*, const QPoint&, int) ),
             this, SLOT( browseItem() ));
    connect( this, SIGNAL( contextMenu(KListView*, QListViewItem*, const QPoint&) ),
             this, SLOT( showContextMenu(KListView*, QListViewItem*, const QPoint&) ));
}

ChannelEditor::~ChannelEditor()
{
}

void ChannelEditor::setChannels( ChannelStore *chans )
{
    clear();
    cs = chans;
    createItems();
    connect(cs, SIGNAL(channelAdded(Channel*)), this, SLOT(reloadChannels()));
    connect(cs, SIGNAL(channelRemoved(Channel*)), this, SLOT(reloadChannels()));
    connect(cs, SIGNAL(aboutToReload()), this, SLOT(storeCurrentChannel()));
    connect(cs, SIGNAL(loaded()), this, SLOT(reloadChannels()));
}


void ChannelEditor::createItems()
{
    if ( !cs )
        return;

    for ( uint i = 0 ; i < cs->count(); i++ ) {
        Channel *c = cs->channelAt( i );
        if ( c )
            (void) new ChannelListItem( this, c, _showSelectedOnly );
    }
}

void ChannelEditor::showContextMenu(KListView*, QListViewItem*, const QPoint& p)
{
    QListViewItem *item = currentItem();

    if (!item || item->rtti() != CLI_RTTI)
        return;

    ChannelListItem *l = static_cast<ChannelListItem*>(item);

    _pop->changeTitle(_titleId, l->c->name());
    _pop->setItemEnabled(_hpId, !l->c->url().isEmpty());
    _pop->popup(p);
}

void ChannelEditor::browseItem()
{
    QListViewItem *item = currentItem();

    if (!item || item->rtti() != CLI_RTTI)
        return;

    ChannelListItem *l = static_cast<ChannelListItem*>(item);

    if(!l->c->url().isEmpty()) {
        kapp->invokeBrowser(l->c->url());
    }
}

void ChannelEditor::editItem()
{
    QListViewItem *item = currentItem();

    if (!item || item->rtti() != CLI_RTTI)
        return;

    ChannelListItem *l = static_cast<ChannelListItem*>(item);

    QDialog* d = _srcm->channelPropertiesDialog(l->c, this);
    connect(d, SIGNAL(accepted()),
            this, SLOT(slotPropertiesDlgFinished()));
    connect(d, SIGNAL(rejected()),
            this, SLOT(slotPropertiesDlgFinished()));

    d->show();
}


void ChannelEditor::slotPropertiesDlgFinished()
{
    QListViewItem *item = currentItem();

    if (!item || item->rtti() != CLI_RTTI)
        return;

    ChannelListItem *l = static_cast<ChannelListItem*>(item);

    emit channelSelected(l->c);
}


void ChannelEditor::renameItem( QListViewItem *item, const QString &str, int /*col*/ )
{
    if (!item || item->rtti() != CLI_RTTI)
        return;

    ChannelListItem *l = static_cast<ChannelListItem*>(item);
    l->c->setName( str );
    emit channelModified( l->c );
}


void ChannelEditor::requestChange(QListViewItem *item)
{
    if (!item || item->rtti() != CLI_RTTI)
        return;

    ChannelListItem *l = static_cast<ChannelListItem*>(item);
    emit channelSelected(l->c);
}


void ChannelEditor::ensureSelected(Channel *ch)
{
    ChannelListItem *x = static_cast<ChannelListItem*>(firstChild());

    while (x) {
        if (x->rtti() == CLI_RTTI && x->c == ch) {
            // Block signals here before selecting the current
            // channel inorder to avoid ::setChannel from being
            // invoked again...
            bool block = signalsBlocked();
            blockSignals (true);
            setCurrentItem(x);
            ensureItemVisible(x);
            setSelected(x, true);
            repaintItem(x);
            x->setSelected(true);
            blockSignals (block);
            //kdDebug() << "Ensuring item is selected: " << x->c->number() << endl;
            return;
        }
        x = static_cast<ChannelListItem *>(x->nextSibling());
    }
}


void ChannelEditor::reloadChannels()
{
    clear();
    createItems();
    //resize(columnWidth(0)+columnWidth(1)+8, height());
}


void ChannelEditor::slotSetShowSelectedOnly(bool sso)
{
    _showSelectedOnly = sso;
    storeCurrentChannel();

    // re-create items & restore selection
    restoreCurrentChannel();
    return;
} // showSelectedOnly


void ChannelEditor::storeCurrentChannel()
{
    ChannelListItem* l = static_cast<ChannelListItem*>(currentItem());
    prev = l ? l->c->number() : 0;
}


void ChannelEditor::restoreCurrentChannel()
{
    reloadChannels();
    if (prev != 0)
        ensureSelected(cs->channelNumber(prev));
}
