/*
    channellist.cpp - IRC Channel Search Widget

    Copyright (c) 2004      by Jason Keirstead <jason@keirstead.org>

    Kopete    (c) 2002-2004 by the Kopete developers <kopete-devel@kde.org>

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

#include "channellist.h"

#include "kircengine.h"

#include <tdelocale.h>
#include <tdemessagebox.h>

#include <tqvariant.h>
#include <tqlabel.h>
#include <tqpainter.h>
#include <tqapplication.h>
#include <tqsimplerichtext.h>
#include <tqstyle.h>
#include <tqlineedit.h>
#include <tqpushbutton.h>
#include <tqheader.h>
#include <tdelistview.h>
#include <tqlayout.h>
#include <tqtooltip.h>
#include <tqtimer.h>
#include <tqspinbox.h>
#include <tqwhatsthis.h>

class ChannelListItem : public TDEListViewItem
{
	public:
		ChannelListItem( TDEListView *parent, TQString arg1, TQString arg2, TQString arg3 );
		virtual int compare( TQListViewItem *i, int col, bool ascending ) const;
		virtual void paintCell( TQPainter *p, const TQColorGroup &cg, int column, int width, int align );

	private:
		TDEListView *parentList;
};

ChannelListItem::ChannelListItem( TDEListView *parent, TQString arg1, TQString arg2, TQString arg3 ) :
	TDEListViewItem( parent, parent->lastItem() ), parentList( parent )
{
	setText(0, arg1);
	setText(1, arg2);
	setText(2, arg3);
}

int ChannelListItem::compare( TQListViewItem *i, int col, bool ascending ) const
{
	if( col == 1 )
	{
		if( text(1).toUInt() < i->text(1).toUInt() )
			return -1;
		else if ( text(1).toUInt() == i->text(1).toUInt() )
			return 0;
		else
			return 1;
	}
	else
		return TQListViewItem::compare( i, col, ascending );
}

void ChannelListItem::paintCell( TQPainter *p, const TQColorGroup &cg, int column, int width, int align )
{
	TQPixmap back( width, height() );
	TQPainter paint( &back );
	//TDEListViewItem::paintCell( &paint, cg, column, width, align );
	// PASTED FROM KLISTVIEWITEM:
	// set the alternate cell background colour if necessary
	TQColorGroup _cg = cg;
	if (isAlternate())
		if (listView()->viewport()->backgroundMode()==TQt::FixedColor)
			_cg.setColor(TQColorGroup::Background, static_cast< TDEListView* >(listView())->alternateBackground());
		else
			_cg.setColor(TQColorGroup::Base, static_cast< TDEListView* >(listView())->alternateBackground());
	// PASTED FROM TQLISTVIEWITEM
	{
		TQPainter *p = &paint;

		TQListView *lv = listView();
		if ( !lv )
			return;
		TQFontMetrics fm( p->fontMetrics() );

		// any text we render is done by the Components, not by this class, so make sure we've nothing to write
		TQString t;

		// removed text truncating code from TQt - we do that differently, further on

		int marg = lv->itemMargin();
		int r = marg;
	//	const TQPixmap * icon = pixmap( column );

		const BackgroundMode bgmode = lv->viewport()->backgroundMode();
		const TQColorGroup::ColorRole crole = TQPalette::backgroundRoleFromMode( bgmode );

		if ( _cg.brush( crole ) != lv->colorGroup().brush( crole ) )
			p->fillRect( 0, 0, width, height(), _cg.brush( crole ) );
		else
		{
			// all copied from TQListView::paintEmptyArea

			//lv->paintEmptyArea( p, TQRect( 0, 0, width, height() ) );
			TQStyleOption opt( lv->sortColumn(), 0 ); // ### hack; in 3.1, add a property in TQListView and TQHeader
			TQStyle::SFlags how = TQStyle::Style_Default;
			if ( lv->isEnabled() )
				how |= TQStyle::Style_Enabled;

			lv->style().drawComplexControl( TQStyle::CC_ListView,
						p, lv, TQRect( 0, 0, width, height() ), lv->colorGroup(),
						how, TQStyle::SC_ListView, TQStyle::SC_None,
						opt );
		}



		if ( isSelected() &&
		(column == 0 || lv->allColumnsShowFocus()) ) {
			p->fillRect( r - marg, 0, width - r + marg, height(),
					_cg.brush( TQColorGroup::Highlight ) );
	// removed text pen setting code from TQt
		}

		// removed icon drawing code from TQt

		// draw the tree gubbins
		if ( multiLinesEnabled() && column == 0 && isOpen() && childCount() ) {
			int textheight = fm.size( align, t ).height() + 2 * lv->itemMargin();
			textheight = TQMAX( textheight, TQApplication::globalStrut().height() );
			if ( textheight % 2 > 0 )
				textheight++;
			if ( textheight < height() ) {
				int w = lv->treeStepSize() / 2;
				lv->style().drawComplexControl( TQStyle::CC_ListView, p, lv,
								TQRect( 0, textheight, w + 1, height() - textheight + 1 ), _cg,
								lv->isEnabled() ? TQStyle::Style_Enabled : TQStyle::Style_Default,
								TQStyle::SC_ListViewExpand,
								(uint)TQStyle::SC_All, TQStyleOption( this ) );
			}
		}
	}
	// END OF PASTE


	//do you see a better way to tell the TextComponent we are selected ?  - Olivier 2004-09-02
	if ( isSelected() )
		_cg.setColor(TQColorGroup::Text , _cg.highlightedText() );

	TQSimpleRichText myrichtext( text(column), paint.font() );
	myrichtext.draw(  &paint, 0, 0, paint.window(), _cg );

	paint.end();
	p->drawPixmap( 0, 0, back );
}

ChannelList::ChannelList( TQWidget* parent, KIRC::Engine *engine )
    : TQWidget( parent ), m_engine( engine )
{
	ChannelListLayout = new TQVBoxLayout( this, 11, 6, "ChannelListLayout");

	layout72_2 = new TQHBoxLayout( 0, 0, 6, "layout72_2");

	textLabel1_2 = new TQLabel( this, "textLabel1_2" );
	layout72_2->addWidget( textLabel1_2 );

	channelSearch = new TQLineEdit( this, "channelSearch" );
	layout72_2->addWidget( channelSearch );

	numUsers = new TQSpinBox( 0, 32767, 1, this, "num_users" );
	numUsers->setSuffix( i18n(" members") );
	layout72_2->addWidget( numUsers );

	mSearchButton = new TQPushButton( this, "mSearchButton" );
	layout72_2->addWidget( mSearchButton );
	ChannelListLayout->addLayout( layout72_2 );

	mChannelList = new TDEListView( this, "mChannelList" );
	mChannelList->addColumn( i18n( "Channel" ) );
	mChannelList->addColumn( i18n( "Users" ) );
	mChannelList->header()->setResizeEnabled( FALSE, mChannelList->header()->count() - 1 );
	mChannelList->addColumn( i18n( "Topic" ) );
	mChannelList->setAllColumnsShowFocus( TRUE );
	mChannelList->setShowSortIndicator( TRUE );
	ChannelListLayout->addWidget( mChannelList );

	clearWState( WState_Polished );

	textLabel1_2->setText( i18n( "Search for:" ) );
	TQToolTip::add( textLabel1_2, i18n( "You may search for channels on the IRC server for a text string entered here." ) );
	TQToolTip::add( numUsers, i18n( "Channels returned must have at least this many members." ) );
	TQWhatsThis::add( numUsers, i18n( "Channels returned must have at least this many members." ) );
	TQWhatsThis::add( textLabel1_2, i18n( "You may search for channels on the IRC server for a text string entered here.  For instance, you may type 'linux' to find channels that have something to do with linux." ) );
	TQToolTip::add( channelSearch, i18n( "You may search for channels on the IRC server for a text string entered here." ) );
	TQWhatsThis::add( channelSearch, i18n( "You may search for channels on the IRC server for a text string entered here.  For instance, you may type 'linux' to find channels that have something to do with linux." ) );
	mSearchButton->setText( i18n( "S&earch" ) );
	TQToolTip::add( mSearchButton, i18n( "Perform a channel search." ) );
	TQWhatsThis::add( mSearchButton, i18n( "Perform a channel search.  Please be patient, as this can be slow depending on the number of channels on the server." ) );
	TQToolTip::add( mChannelList, i18n( "Double click on a channel to select it." ) );
	mChannelList->header()->setLabel( 0, i18n( "Channel" ) );
	mChannelList->header()->setLabel( 1, i18n( "Users" ) );
	mChannelList->header()->setLabel( 2, i18n( "Topic" ) );

	// signals and slots connections
	connect( mChannelList, TQ_SIGNAL( doubleClicked(TQListViewItem*) ),
		this, TQ_SLOT( slotItemDoubleClicked(TQListViewItem*) ) );

	connect( mSearchButton, TQ_SIGNAL( clicked() ), this, TQ_SLOT( search() ) );

	connect( mChannelList, TQ_SIGNAL( selectionChanged( TQListViewItem*) ), this,
		TQ_SLOT( slotItemSelected( TQListViewItem *) ) );

	connect( m_engine, TQ_SIGNAL( incomingListedChan( const TQString &, uint, const TQString & ) ),
		this, TQ_SLOT( slotChannelListed( const TQString &, uint, const TQString & ) ) );

	connect( m_engine, TQ_SIGNAL( incomingEndOfList() ), this, TQ_SLOT( slotListEnd() ) );

	connect( m_engine, TQ_SIGNAL( statusChanged(KIRC::Engine::Status) ),
			this, TQ_SLOT( slotStatusChanged(KIRC::Engine::Status) ) );

	show();
}

void ChannelList::slotItemDoubleClicked( TQListViewItem *i )
{
	emit channelDoubleClicked( i->text(0) );
}

void ChannelList::slotItemSelected( TQListViewItem *i )
{
	emit channelSelected( i->text(0) );
}

void ChannelList::slotStatusChanged(KIRC::Engine::Status newStatus)
{
	switch(newStatus) {
	case KIRC::Engine::Connected:
		this->reset();
		break;
	case KIRC::Engine::Disconnected:
		if (mSearching) {
			KMessageBox::queuedMessageBox(
				this, KMessageBox::Error,
				i18n("You have been disconnected from the IRC server."),
				i18n("Disconnected"), 0
				);
		}

		slotListEnd();
		break;
	default:
		break;
	}
}

void ChannelList::reset()
{
	channelCache.clear();
	clear();
}

void ChannelList::clear()
{
	mChannelList->clear();
	channelSearch->clear();
	channelSearch->setFocus();
}

void ChannelList::search()
{
	if( m_engine->isConnected() || !channelCache.isEmpty() )
	{
		mChannelList->clear();
		mChannelList->setSorting( -1 );
		mSearchButton->setEnabled(false);
		mSearch = channelSearch->text();
		mSearching = true;
		mUsers = numUsers->value();

		if( channelCache.isEmpty() )
			m_engine->list();
		else
		{
			cacheIterator = channelCache.begin();
			slotSearchCache();
		}
	}
	else
	{
		KMessageBox::queuedMessageBox(
			this, KMessageBox::Error,
			i18n("You must be connected to the IRC server to perform a channel listing."),
			i18n("Not Connected"), 0
		);
	}
}

void ChannelList::slotChannelListed( const TQString &channel, uint users, const TQString &topic )
{
	checkSearchResult( channel, users, topic );
	channelCache.insert( channel, TQPair< uint, TQString >( users, topic ) );
}

void ChannelList::checkSearchResult( const TQString &channel, uint users, const TQString &topic )
{
	if( ( mUsers == 0 || mUsers <= users ) &&
		( mSearch.isEmpty() || channel.contains( mSearch, false ) || topic.contains( mSearch, false ) )
	)
	{
		new ChannelListItem( mChannelList, channel, TQString::number(users), topic );
	}
}

void ChannelList::slotSearchCache()
{
	if( cacheIterator != channelCache.end() )
	{
		checkSearchResult( cacheIterator.key(), cacheIterator.data().first, cacheIterator.data().second );
		++cacheIterator;
		TQTimer::singleShot( 0, this, TQ_SLOT( slotSearchCache() ) );
	}
	else
	{
		slotListEnd();
	}
}

void ChannelList::slotListEnd()
{
	mChannelList->setSorting(0, true);
	mSearchButton->setEnabled(true);
	mSearching = false;
}

#include "channellist.moc"
