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

#include <stdlib.h>

#include <qtoolbar.h>
#include <qtabbar.h>
//Added by qt3to4:
#include <QEvent>
#include <QMdiArea>
#include <QMdiSubWindow>

#include "dcclient.h"
#include "dciconloader.h"
#include "dcconfig.h"

#include <dclib/dcos.h>

DCConnectionManager * g_pConnectionManager = 0;

/** */
DCConnectionManager::DCConnectionManager( QObject * parent ) : QObject( parent )
{
	m_pMdiArea = qobject_cast<QMdiArea*>(parent);
	
	m_pMessageList = new QList<CDCMessage*>();

	InitDocument();

	g_pConnectionManager = this;
}

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

	g_pConnectionManager = NULL;

	m_Mutex.Lock();

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

	if ( m_pMessageList )
	{
		QList<CDCMessage*> * tmp = m_pMessageList;
		m_pMessageList = 0;
		
		for ( QList<CDCMessage*>::const_iterator it = tmp->constBegin(); it != tmp->constEnd(); ++it )
		{
			delete *it;
		}
		
		delete tmp;
	}
	
	m_ClientsInTabOrder.clear();

	m_Mutex.UnLock();
}

/** */
void DCConnectionManager::InitDocument()
{
	m_pTabBar = 0;
	m_nSelectedTab = -1;
	
	connect( &m_Timer, SIGNAL(timeout()), this, SLOT(timerDone()) );

	connect( m_pMdiArea, SIGNAL(subWindowActivated(QMdiSubWindow *)), this, SLOT(slotMdiSubWindowActivated( QMdiSubWindow *)) );
	
	m_Timer.setSingleShot( true );
	m_Timer.start( 500 );
}

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

/** */
void DCConnectionManager::slotTabSelected( int id )
{
	if ( (m_nSelectedTab != id) && (id >= 0) && (id < m_ClientsInTabOrder.size()) )
	{
		DCClient * client = m_ClientsInTabOrder.at(id);
		m_pTabBar->setTabIcon(id,QIcon());
		m_pMdiArea->setActiveSubWindow(client->GetMdiSubWindow());
	}
	
	m_nSelectedTab = id;
}

/** widget from mdi area activated */
void DCConnectionManager::slotMdiSubWindowActivated( QMdiSubWindow * w )
{
	if ( w && w->widget() )
	{
		DCClient * client = qobject_cast<DCClient*>(w->widget());
		
		if ( client )
		{
			const int index = m_ClientsInTabOrder.indexOf( client );
			
			if ( index != m_nSelectedTab )
			{
				m_nSelectedTab = index;
				m_pTabBar->setCurrentIndex( index );
				m_pTabBar->setTabIcon( index, QIcon() );
			}
		}
	}
}

/** */
void DCConnectionManager::HubEvent( DCClient * client )
{
	if ( !client )
		return;
	
	int i = m_ClientsInTabOrder.indexOf(client);
	if ( (i != -1) && (i != m_pTabBar->currentIndex()) )
	{
		m_pTabBar->setTabIcon( i, QIcon(g_pIconLoader->GetPixmap(eiMESSAGE)) );
	}
}

/** */
void DCConnectionManager::CaptionChanged( DCClient * client )
{
	if ( client )
	{
		const int i = m_ClientsInTabOrder.indexOf( client );
		
		if ( (i >= 0) && (i < m_pTabBar->count()) )
		{
			QString s = QString::fromAscii( client->GetHubName().Data() );
			if ( s.length() > 20 )
			{
				s = s.left(20) + "...";
			}
			m_pTabBar->setTabText( i, s );
		}
	}
}

/** */
void DCConnectionManager::HubClosing( DCClient * client )
{
	/*
	 * Strangely, hubs are not deleted in dclib CConnectionManager
	 * but are deleted by QT after being closed because the delete
	 * on close flag is set.
	 */
	if ( client )
	{
		const int i = m_ClientsInTabOrder.indexOf( client );
		
		if ( i != -1 )
		{
			m_ClientsInTabOrder.removeAt(i);
			
			/*
			 * FIXME disconnect/connect to stop QT 4.3 crashing.
			 * The crash was before slotTabSelected got called.
			 * QT 4.4 did not crash.
			 * So possibly there is some other bug or it's a QT bug that's already fixed.
			 */
			disconnect( m_pTabBar, SIGNAL(currentChanged(int)), this, SLOT(slotTabSelected(int)) );
			m_pTabBar->removeTab(i);
			connect( m_pTabBar, SIGNAL(currentChanged(int)), this, SLOT(slotTabSelected(int)) );
		}
		
		if ( m_pTabBar->count() == 0 )
		{
			m_pTabBar->hide();
		}
		
		RemoveHub( client );
		
		// do not change m_nSelectedTab , tab is not selected anymore
	}
}

/** callback function */
int DCConnectionManager::DC_CallBack( CDCMessage * DCMessage )
{
	int err = -1;

	m_Mutex.Lock();

	if ( DCMessage && m_pMessageList )
	{
		m_pMessageList->append(DCMessage);
		err = 0;
	}

	m_Mutex.UnLock();

	return err;
}

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

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

		if ( m_pMessageList && !m_pMessageList->isEmpty() )
		{
			DCMsg = m_pMessageList->takeFirst();
		}
		else
		{
			DCMsg = 0;
		}

		m_Mutex.UnLock();

		if ( DCMsg == 0 )
		{
			break;
		}

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

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

				break;
			}

			default:
			{
				break;
			}
		}

		if ( DCMsg )
		{
			delete DCMsg;
		}
	}

	m_Timer.setSingleShot( true );
	m_Timer.start( 500 );
}

/** */
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 ) )
		{
			if ( ConfigHubProfile.m_bAutoConnect )
			{
				Connect( hubitem->m_sName, hubitem->m_sHost );
			}
		}
	}
}

/** */
void DCConnectionManager::Connect( CString hubname, CString server, bool sslconnect )
{
	if ( server.IsEmpty() )
	{
		return;
	}

	if ( hubname.IsEmpty() )
	{
		hubname = server;
	}

	m_Mutex.Lock();

	DCClient * client = dynamic_cast<DCClient*>(GetHub(hubname,server));

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

	m_Mutex.UnLock();

	if ( client )
	{
		return;
	}

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

	client = new DCClient(m_pMdiArea,g_pConfig->GetRemoteEncoding(hubname,server));
	client->setObjectName(s);
	client->setAttribute(Qt::WA_DeleteOnClose);
	
	s = QString::fromAscii(client->GetHubName().Data());
	if ( s.length() > 20 )
		s = s.left(20) + "...";

	if ( m_pTabBar->count() == 0 )
		m_pTabBar->show();
	
	m_pTabBar->addTab( QIcon(), s );
	m_ClientsInTabOrder.append(client);

	client->setWindowTitle(QString::fromAscii(hubname.Data()));

	if ( g_pConfig->GetOpenClientWindows() == 0 )
	{
		client->showMinimized();
	}
	else if ( g_pConfig->GetOpenClientWindows() == 2 )
	{
		client->showMaximized();
		client->GetMdiSubWindow()->showMaximized();
		// update tabbar
		slotMdiSubWindowActivated(client->GetMdiSubWindow());
	}
	else
	{
		client->show();
		client->GetMdiSubWindow()->show();
		client->centreOnMdiArea();
		// update tabbar
		slotMdiSubWindowActivated(client->GetMdiSubWindow());
	}

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

/** */
void DCConnectionManager::OpenPrivateChat( QString hubname, QString hubhost, QString nick )
{
      	m_Mutex.Lock();

	DCClient * Client = dynamic_cast<DCClient*>(GetHub(hubname.toAscii().constData(),hubhost.toAscii().constData()));

	if ( Client )
	{
		Client->DC_PrivateChat(nick,QString(),QString(),true);
	}

	m_Mutex.UnLock();
}

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

	m_Mutex.Lock();

	while( (Client=m_pClientList->Next(Client)) != 0 )
	{
		DCClient * dcc = dynamic_cast<DCClient*>(Client);
		if ( dcc )
		{
			dcc->CloseAllChats( onlyOffline );
		}
	}

	m_Mutex.UnLock();
}

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

	m_Mutex.Lock();

	while( (Client=m_pClientList->Next(Client)) != 0 )
	{
		m_Mutex.UnLock();
		Client->Disconnect(true);
		m_Mutex.Lock();
	}

	m_Mutex.UnLock();
}

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

	m_Mutex.Lock();

	while( (Client=m_pClientList->Next(Client)) != 0 )
	{
		if ( Client->GetConnectionState() == estNONE )
		{
			m_Mutex.UnLock();
			DCClient * dcc = dynamic_cast<DCClient*>(Client);
			if ( dcc )
			{
				dcc->GetMdiSubWindow()->close();
			}
			m_Mutex.Lock();

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

	m_Mutex.UnLock();
}

/** */
void DCConnectionManager::OPKick( QString hubname, QString hubhost, QString nick, QString message )
{
	m_Mutex.Lock();

	DCClient * Client = dynamic_cast<DCClient*>(GetHub(hubname.toAscii().constData(),hubhost.toAscii().constData()));

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

	m_Mutex.UnLock();
}

/** */
void DCConnectionManager::OPForceMove( QString hubname, QString hubhost, QString nick, QString message, QString host )
{
	m_Mutex.Lock();

        DCClient * Client = dynamic_cast<DCClient*>(GetHub(hubname.toAscii().constData(),hubhost.toAscii().constData()));

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

	m_Mutex.UnLock();
}

/** */
DCClient * DCConnectionManager::GetClientForHub( CString hubname, CString hubhost )
{
	/* using dynamic_cast because there could be non gui CClients
	 * present if doing bookmark/public hub search
	 */
	return dynamic_cast<DCClient*>(GetHub( hubname, hubhost ));
}
