/***************************************************************************
                          dcconnectionmanager.cpp  -  description
                             -------------------
    begin                : Mon Oct 1 2001
    copyright            : (C) 2001-2005 by Mathias Küster
    email                : mathen@users.berlios.de
 ***************************************************************************/

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

#include <qapplication.h>
#include <qobject.h>
#include <qpainter.h>
#include <qlistview.h>
#include <qpushbutton.h>
#include <qtoolbutton.h>
#include <qlineedit.h>
#include <qpopupmenu.h>
#include <qcursor.h>
#include <qstringlist.h>
#include <qtabwidget.h>
#include <qinputdialog.h>
#include <qcombobox.h>
#include <qregexp.h>
#include <qcheckbox.h>
#include <qmessagebox.h>
#include <qtoolbar.h>

#include <dcgeturl.h>
#include <dcclient.h>
#include <dcmenuhandler.h>
#include <dcwidget.h>
#include <dchubprofile.h>
#include <dchubfilter.h>
#include <dciconloader.h>

#include "dcconnectionmanager.h"

#include <dclib/dcos.h>
#include <dclib/core/cbz.h>
#include <dclib/chttp.h>

#include "dceditserver.h"
#include "cdialogmessage.h"

DCConnectionManager * g_pConnectionManager = 0;

/** */
DCConnectionManager::DCConnectionManager( QWidget * parent, const char *name, int wflags) : DCDialogConnectionManager(parent, name, wflags)
{
	// set default icon
	setIcon( g_pIconLoader->GetPixmap(eiSERVER) );

	m_pWorkspace = (QWorkspace*)parent;

	m_pMessageList = new CList<CObject>();

	InitDocument();

	g_pConnectionManager = this;
}

/** */
DCConnectionManager::~DCConnectionManager()
{
	DCClient * Client = 0;

	g_pConnectionManager = NULL;

	m_Thread.Lock();

	while( (Client=(DCClient*)m_pClientList->Next(0)) != 0 )
	{
		Client->removeEventFilter(this);
		m_pClientList->Remove(Client);
		Client->Disconnect();
	}

	if ( m_pMessageList )
	{
		delete m_pMessageList;
		m_pMessageList = 0;
	}

	m_Thread.UnLock();
}

/** */
void DCConnectionManager::InitDocument()
{
	StringMap * map;

	m_pTabBar = 0;
	m_nSelectedTab = -1;
	m_bDisableTabSelected = FALSE;
	
	// restore settings
	if ( g_pConfig->GetMap("CONNECTIONVIEW",map) == TRUE )
	{
		if ( ((*map)["WIDTH"].toInt() > 0) && ((*map)["HEIGHT"].toInt() > 0) )
		{
			setGeometry( (*map)["X"].toInt(), (*map)["Y"].toInt(), (*map)["WIDTH"].toInt(), (*map)["HEIGHT"].toInt() );
		}
	}

	connect( &m_Timer, SIGNAL(timeout()), this, SLOT(timerDone()) );

	connect( m_pWorkspace, SIGNAL(windowActivated(QWidget *)), this, SLOT(slotWorkspaceWindowActivated( QWidget *)) );
	
	m_Timer.start( 500, TRUE );
}

/** */
void DCConnectionManager::InitTabBar( QToolBar * toolbar )
{
	m_pTabBar = new QTabBar(toolbar);
	toolbar->setStretchableWidget(m_pTabBar);
	connect(m_pTabBar, SIGNAL(selected(int)), this, SLOT(slotTabSelected(int)));
	// hide empty tabbar
	m_pTabBar->hide();
}

/** */
void DCConnectionManager::resetTabIcon( DCClientTab * ct )
{
	if ( !ct )
		return;

	ct->setIconSet( QIconSet() );
	// little trick to force a repaint/resize
	ct->setText(ct->text());
}

/** */
void DCConnectionManager::slotTabSelected( int id )
{
	int i;

	if ( m_bDisableTabSelected )
	{
		m_bDisableTabSelected = FALSE;
	}
	else if ( (id != -1) && (m_nSelectedTab != id) )
	{
		i = m_pTabBar->indexOf(id);
		
		if ( i != -1 )
		{
			DCClientTab * ct = (DCClientTab *)m_pTabBar->tabAt(i);
			
			if ( ct )
			{
				resetTabIcon(ct);
				if ( ct->m_pClient )
					ct->m_pClient->showNormal();
			}
		}
	}
	
	m_nSelectedTab = id;
}

/** overridden so that the columns are resized on show() */
void DCConnectionManager::show()
{
	QWidget::show();
}

/** */
int DCConnectionManager::selectedItems( QListView * list, QPtrList<QListViewItem> & lst )
{
	QListViewItemIterator it( (QListView *)list );

	for ( ; it.current(); it++ )
	{
		if ( it.current()->isSelected() )
		{
			lst.append(it.current());
		}
	}

	return lst.count();
}

/** */
void DCConnectionManager::DeInitDocument()
{
	StringMap * map;

	// save hub view settings
	g_pConfig->GetMap("CONNECTIONVIEW",map);

	(*map)["X"]          = QString().setNum(parentWidget()->x());
	(*map)["Y"]          = QString().setNum(parentWidget()->y());
	(*map)["WIDTH"]      = QString().setNum(width());
	(*map)["HEIGHT"]     = QString().setNum(height());
	(*map)["VISIBLE"]    = QString().setNum(isVisible());
	(*map)["MAXIMIZED"]  = QString().setNum(isMaximized());
	(*map)["MINIMIZED"]  = QString().setNum(isMinimized());
	(*map)["ENABLED"]    = QString().setNum(isEnabled());

	if ( !isEnabled() )
	{
		setEnabled(TRUE);
	}
}

/** event filter */
bool DCConnectionManager::eventFilter(QObject* object, QEvent* event)
{
	if ( (DCConnectionManager*)object != this )
	{
		DCClient* pView=(DCClient*)object;

		if ( event->type() == QEvent::Close )
		{
			// remove tab
			int i;
			for(i=0;i<m_pTabBar->count();i++)
			{
				DCClientTab * ct = (DCClientTab *)m_pTabBar->tabAt(i);
			
				if ( ct->m_pClient == pView )
				{
					m_pTabBar->removeTab(ct);
					break;
				}	
			}

			if ( m_pTabBar->count() == 0 )
				m_pTabBar->hide();

			pView->showNormal();
			pView->Disconnect(TRUE);
			pView->DeInitDocument();

			RemoveHub(pView);
			
			// update current tab
			m_nSelectedTab = m_pTabBar->currentTab();
		}
		else if ( event->type() == QEvent::CaptionChange )
		{
			// change caption
			int i;
			for(i=0;i<m_pTabBar->count();i++)
			{
				CString s;
				DCClientTab * ct = (DCClientTab *)m_pTabBar->tabAt(i);

				if ( ct->m_pClient == pView )
				{
					s = ct->m_pClient->GetHubName();
					if ( s.Length() > 20 )
						s = s.Left(20) + "...";
					ct->setText( s.Data() );
					break;
				}	
			}
		}
	}

	return QWidget::eventFilter( object, event );    // standard event processing
}

/** widget from workspace activated */
void DCConnectionManager::slotWorkspaceWindowActivated( QWidget * w )
{
	DCClientTab * ct = 0;
	int id = m_pTabBar->currentTab();
			
	if ( id != -1 )
		ct = (DCClientTab *)m_pTabBar->tabAt( m_pTabBar->indexOf(id) );

	if ( ct && w )
	{
		// only if tab change
		if ( ct->m_pClient != w )
		{
			// set current tab
			int i;
			
			for(i=0;i<m_pTabBar->count();i++)
			{
				DCClientTab * ct = (DCClientTab *)m_pTabBar->tabAt(i);

				if ( ct && ct->m_pClient == w )
				{
					m_bDisableTabSelected = TRUE;
					m_pTabBar->setCurrentTab(ct);
					resetTabIcon(ct);

					break;
				}
			}
		}
	}
}

/** */
void DCConnectionManager::HubEvent( DCClient * client )
{
	int i;

	if ( !client )
		return;
		
	for(i=0;i<m_pTabBar->count();i++)
	{
		CString s;
		DCClientTab * ct = (DCClientTab *)m_pTabBar->tabAt(i);

		if ( ct->m_pClient == client )
		{
			DCClientTab * ctw = 0;
			int id = m_pTabBar->currentTab();
			
			if ( id != -1 )
				ctw = (DCClientTab *)m_pTabBar->tabAt( m_pTabBar->indexOf(id) );

			if ( ct != ctw )
			{
				ct->setIconSet( QIconSet( g_pIconLoader->GetPixmap(eiMESSAGE) ) );
				// little trick to force a repaint/resize
				ct->setText(ct->text());
			}

			break;
		}	
	}
}

/** callback function */
int DCConnectionManager::DC_CallBack( CObject * Object )
{
	int err;

	m_Thread.Lock();

	if ( Object != NULL )
	{
		if ( m_pMessageList != NULL )
		{
			m_pMessageList->Add(Object);
			err = 0;
		}
		else
		{
			err = -1;
		}
	}
	else
	{
		err = -1;
	}

	m_Thread.UnLock();

	return err;
}

/** */
void DCConnectionManager::timerDone()
{
	CObject * Object;
	CDCMessage *DCMsg;
	int i;

	for(i=0;i<50;i++)
	{
		if ( m_Thread.TryLock() == FALSE )
		{
			break;
		}

		if ( m_pMessageList != 0 )
		{
			Object = m_pMessageList->Next(0);

			if ( Object != 0 )
			{
				m_pMessageList->Remove(Object);
			}
		}
		else
		{
			Object = 0;
		}

		m_Thread.UnLock();

		if ( Object == 0 )
		{
			break;
		}

		DCMsg = (CDCMessage*) Object;

		switch ( DCMsg->m_eType )
		{
			case DC_MESSAGE_CONNECT_CLIENT:
			{
				DCMessageConnectClient *msg = (DCMessageConnectClient*)Object;

				Connect( msg->m_sHubName, msg->m_sHubHost );

				break;
			}

			default:
			{
				break;
			}
		}

		if ( Object )
		{
			delete Object;
		}
	}

	m_Timer.start( 500, TRUE );
}

/** */
void DCConnectionManager::AutoConnect()
{
	DCConfigHubItem * hubitem = 0;
	CList<DCConfigHubItem> list;
	DCConfigHubProfile ConfigHubProfile;

	g_pConfig->GetBookmarkHubList(&list);

	while( (hubitem=list.Next(hubitem)) != 0 )
	{
		// check for autoconnect
		if ( g_pConfig->GetHubProfile( hubitem->m_sProfile, &ConfigHubProfile ) == TRUE )
		{
			if ( ConfigHubProfile.m_bAutoConnect == TRUE )
			{
				Connect( hubitem->m_sName.Data(), hubitem->m_sHost.Data() );
			}
		}
	}
}

/** */
void DCConnectionManager::Connect( CString hubname, CString server, bool sslconnect )
{
	int i;
	CString s;
	DCClient * client;

	if ( server == "" )
	{
		return;
	}

	if ( hubname == "" )
	{
		hubname = server;
	}

	m_Thread.Lock();

	client = (DCClient*)GetHub(hubname,server);

	if ( client )
	{
		client->setFocus();
	}

	m_Thread.UnLock();

	if ( client )
	{
		return;
	}

	if ( (i = server.Find(':')) >= 0 )
	{
		s = server.Left(i);
	}
	else
	{
		s = server;
	}

	client = new DCClient(m_pWorkspace,s.Data(),WDestructiveClose);
	client->installEventFilter(this);

	// create tab
	DCClientTab * ct = new DCClientTab();
	
	ct->m_pClient = client;
	s = ct->m_pClient->GetHubName();
	if ( s.Length() > 20 )
		s = s.Left(20) + "...";
	ct->setText(s.Data());

	if ( m_pTabBar->count() == 0 )
		m_pTabBar->show();
	m_pTabBar->addTab(ct);

	client->setCaption(hubname.Data());

	if ( !g_pConfig->GetOpenClientWindowsMinimized() )
	{
		client->showNormal();
		// update tabbar
		slotWorkspaceWindowActivated(client);
	}
	else
	{
		client->showMinimized();
	}

	CConnectionManager::Connect(hubname,server,client,sslconnect);
}

/** */
void DCConnectionManager::OpenPrivateChat( QString hubname, QString hubhost, QString nick )
{
        DCClient * Client = 0;

	m_Thread.Lock();

	Client = (DCClient*)GetHub(hubname.ascii(),hubhost.ascii());

	if ( Client )
	{
		Client->DC_PrivateChat(nick,"","",TRUE);
	}

	m_Thread.UnLock();
}

/** */
void DCConnectionManager::CloseAllChats()
{
	CClient * Client = 0;

	m_Thread.Lock();

	while( (Client=m_pClientList->Next(Client)) != 0 )
	{
		((DCClient*)Client)->CloseAllChats();
	}

	m_Thread.UnLock();
}

/** */
void DCConnectionManager::DisconnectAllClients()
{
	CClient * Client = 0;

	m_Thread.Lock();

	while( (Client=m_pClientList->Next(Client)) != 0 )
	{
		m_Thread.UnLock();
		((DCClient*)Client)->Disconnect(TRUE);
		m_Thread.Lock();
	}

	m_Thread.UnLock();
}

/** */
void DCConnectionManager::CloseDisconnectedHubs()
{
	CClient * Client = 0, * oClient = 0;

	m_Thread.Lock();

	while( (Client=m_pClientList->Next(Client)) != 0 )
	{
		if ( ((DCClient*)Client)->GetConnectionState() == estNONE )
		{
			m_Thread.UnLock();
			((DCClient*)Client)->close();
			m_Thread.Lock();

			Client = oClient;
		}
		else
		{
			oClient = Client;
		}
	}

	m_Thread.UnLock();
}

/** */
void DCConnectionManager::OPKick( QString hubname, QString hubhost, QString nick, QString message )
{
        DCClient * Client = 0;

	m_Thread.Lock();

	Client = (DCClient*)GetHub(hubname.ascii(),hubhost.ascii());

	if ( Client )
	{
		Client->OPKick( nick, message );
	}

	m_Thread.UnLock();
}

/** */
void DCConnectionManager::OPForceMove( QString hubname, QString hubhost, QString nick, QString message, QString host )
{
        DCClient * Client = 0;

	m_Thread.Lock();

	Client = (DCClient*)GetHub(hubname.ascii(),hubhost.ascii());

	if ( Client )
	{
		Client->OPForceMove( nick, message, host );
	}

	m_Thread.UnLock();
}
