/***************************************************************************
                          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 <qpushbutton.h>
#include <qlineedit.h>
#include <qcursor.h>
#include <qstringlist.h>
#include <qtabwidget.h>
#include <qinputdialog.h>
#include <qcombobox.h>
#include <qcheckbox.h>
#include <qmessagebox.h>
#include <qtoolbar.h>
//Added by qt3to4:
#include <QEvent>
#include <QMdiArea>
#include <QMdiSubWindow>

#include "dcclient.h"
#include "dchubprofile.h"
#include "dciconloader.h"

#include "dcconnectionmanager.h"

#include <dclib/dcos.h>

DCConnectionManager * g_pConnectionManager = 0;

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

	m_pMdiArea = qobject_cast<QMdiArea*>(parent);
	
	/* if (m_pMdiArea != 0)
	{
		m_pMdiArea->addSubWindow(this);
	} */

	m_pMessageList = new CList<CObject>();
	
	m_pClientTabList = new QList<DCClientTab*>();

	InitDocument();

	g_pConnectionManager = this;
}

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

	g_pConnectionManager = NULL;

	m_Thread.Lock();

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

	if ( m_pMessageList )
	{
		delete m_pMessageList;
		m_pMessageList = 0;
	}
	
	if ( m_pClientTabList )
	{
		for (int i = 0; i < m_pClientTabList->size(); ++i)
		{
			if (m_pClientTabList->at(i) != 0)
			{
				delete m_pClientTabList->at(i);
			}
		}
		
		delete m_pClientTabList;
		m_pClientTabList = 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_pMdiArea, SIGNAL(subWindowActivated(QMdiSubWindow *)), this, SLOT(slotMdiSubWindowActivated( QMdiSubWindow *)) );
	
	m_Timer.start( 500, TRUE );
}

/** */
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::resetTabIcon( DCClientTab * ct )
{
	if ( !ct )
		return;
	
	if (ct->m_nMenuID != -1)
	{
		m_pTabBar->setTabIcon( ct->m_nMenuID, QIcon() );
	}
	
	// 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);
		i = id;
		
		if ( i != -1 )
		{
			DCClientTab * ct = getDCClientTab(i);
			
			if ( ct )
			{
				resetTabIcon(ct);
				if ( ct->m_pClient )
				{
					ct->m_pClient->GetMdiSubWindow()->showNormal();
					ct->m_pClient->GetMdiSubWindow()->raise();
					m_pMdiArea->setActiveSubWindow(ct->m_pClient->GetMdiSubWindow());
				}
			}
		}
	}
	
	m_nSelectedTab = id;
}

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

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

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

	(*map)["X"]          = QString().setNum(x());
	(*map)["Y"]          = QString().setNum(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 )
	{
		QMdiSubWindow * subwin = qobject_cast<QMdiSubWindow*>(object);
		DCClient * dcclient = 0;
		if ( subwin != 0 )
		{
			dcclient = qobject_cast<DCClient*>(subwin->widget());
		}

		if ( event->type() == QEvent::Close )
		{
			// remove tab
			int i;
			for(i=0;i<m_pTabBar->count();i++)
			{
				DCClientTab * ct = getDCClientTab(i);
				
				if (ct != 0)
				{
					if ( ct->m_pClient == dcclient )
					{
						m_pTabBar->removeTab(i);
						m_pClientTabList->removeAt(m_pClientTabList->indexOf(ct));
						delete ct;
						
						break;
					}
				}
			}

			if ( m_pTabBar->count() == 0 )
				m_pTabBar->hide();
			
			dcclient->Disconnect(TRUE);
			dcclient->DeInitDocument();

			RemoveHub(dcclient);
			
			// update current tab
			m_nSelectedTab = m_pTabBar->currentIndex();
			
			subwin->removeEventFilter(this);
			event->accept();
			return TRUE;
		}
		else if ( event->type() == QEvent::CaptionChange )
		{
			// change caption
			int i;
			for(i=0;i<m_pTabBar->count();i++)
			{
				CString s;
				DCClientTab * ct = getDCClientTab(i);

				if ( ct->m_pClient == dcclient )
				{
					s = ct->m_pClient->GetHubName();
					if ( s.Length() > 20 )
						s = s.Left(20) + "...";
					
					m_pTabBar->setTabText(ct->m_nMenuID, s.Data() );
					break;
				}	
			}
		}
	}

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

/** widget from mdi area activated */
void DCConnectionManager::slotMdiSubWindowActivated( QMdiSubWindow * w )
{
	DCClientTab * ct = 0;
	int id = m_pTabBar->currentIndex();
	
	if ( id != -1 )
	{
		ct = getDCClientTab(id);
	}

	if ( ct && w )
	{
		// only if tab change
		if ( ct->m_pClient->GetMdiSubWindow() != w )
		{
			// set current tab
			int i;
			
			for(i=0;i<m_pTabBar->count();i++)
			{
				DCClientTab * ct = getDCClientTab(i);
				
				if ( ct && ct->m_pClient->GetMdiSubWindow() == w )
				{
					m_bDisableTabSelected = TRUE;
					m_pTabBar->setCurrentIndex(ct->m_nMenuID);
					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 = getDCClientTab(i);

		if ( ct->m_pClient == client )
		{
			DCClientTab * ctw = 0;
			int id = m_pTabBar->currentIndex();
			
			if ( id != -1 )
			{
				ctw = getDCClientTab(id);
			}

			if ( ct != ctw )
			{
				m_pTabBar->setTabIcon( ct->m_nMenuID, QIcon(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_pMdiArea,s.Data(),0);
	client->setAttribute(Qt::WA_DeleteOnClose);
	
	//client->installEventFilter(this);
	client->GetMdiSubWindow()->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) + "...";

	if ( m_pTabBar->count() == 0 )
		m_pTabBar->show();
	
	m_pClientTabList->append(ct);
	
	ct->m_nMenuID = m_pTabBar->addTab( QIcon(), s.Data() );

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

	if ( !g_pConfig->GetOpenClientWindowsMinimized() )
	{
		client->showNormal();
		client->InitSizes();
		client->centreOnMdiArea();
		// update tabbar
		slotMdiSubWindowActivated(client->GetMdiSubWindow());
	}
	else
	{
		client->showMinimized();
		client->InitSizes(); // but it probably won't work properly
	}

	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.toAscii().data(),hubhost.toAscii().data());

	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 )
	{
		if ( (DCClient*)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();
		if ( (DCClient*)Client != 0 )
		{
			((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)->GetMdiSubWindow()->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.toAscii().data(),hubhost.toAscii().data());

	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.toAscii().data(),hubhost.toAscii().data());

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

	m_Thread.UnLock();
}

/** */
DCClientTab * DCConnectionManager::getDCClientTab( int index )
{
	DCClientTab * ct = 0;
	
	for (int i = 0; i < m_pClientTabList->size(); ++i)
	{
		if (m_pClientTabList->at(i) != 0)
		{
			if (index == m_pClientTabList->at(i)->m_nMenuID)
			{
				ct = m_pClientTabList->at(i);
				break;
			}
		}
	}
	
	return ct;
}
