/***************************************************************************
                          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>
#include <QTabBar>
#include <QMdiArea>
#include <QMdiSubWindow>
#include <QMapIterator>
#include <QList>

#include <exception>
#include <iostream>

#include "dcclient.h"
#include "dciconloader.h"
#include "dcconfig.h"
#include "dcgui.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;
        QMapIterator<QWidget*, int> it(windowsList);

        while (it.hasNext()){
                QWidget *wgt;
                it.next();
                wgt = it.key();
                delete wgt;
        }

	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_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 DCTabBar(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();

#ifdef QT_NEW
	//m_pTabBar->setTabsClosable(true);
	//m_pTabBar->setMovable(true);

	//connect(m_pTabBar, SIGNAL(tabCloseRequested(int)), this, SLOT(slotCloseTabButtonClicked(int)));
	//connect(m_pTabBar, SIGNAL(tabMoved(int,int)), this, SLOT(slotTabMoved(int,int)));
#endif

}

/** */
void DCConnectionManager::slotTabSelected( int id )
{
        QMapIterator<QWidget*, int> it(windowsList);

        while (it.hasNext()){
            it.next();
            if (it.value() == id){
                    QWidget *wgt = it.key();
                    wgt->setFocus();

                    m_pTabBar->setTabIcon(id, wgt->windowIcon());

                    QMdiSubWindow *mdi_wind;

                    g_pActiveChat = NULL;

                    try{
                        mdi_wind = dynamic_cast<QMdiSubWindow*>(wgt);
                    }
                    catch (std::exception &e){
                        g_pActiveChat = NULL;
                        return;
                    }

                    if (!mdi_wind){
                        return;
                    }

                    DCClient *cl;

                    try{
                        cl = dynamic_cast<DCClient*>(mdi_wind->widget());
                    }
                    catch (std::exception &e){
                        g_pActiveChat = NULL;
                        return;
                    }

                    if (!cl){
                        return;
                    }
                    else{
                        g_pActiveChat = cl->GetChat();
                    }


                return;
            }
        }
}

#ifdef QT_NEW
/*
void DCConnectionManager::slotTabMoved(int from, int to)
{
    QWidget *from_wgt = NULL;
    QWidget *to_wgt   = NULL;

    QMapIterator<QWidget*, int> it(windowsList);

    while (it.hasNext()){
	it.next();

	if (it.value() == from){
	    from_wgt = it.key();
	}
	else if (it.value() == to)
	    to_wgt = it.key();

	if (to_wgt && from_wgt){
	    windowsList[to_wgt] = from;
	    windowsList[from_wgt] = to;

	    slotTabSelected(m_pTabBar->currentIndex());

	    return;
	}
    }
}
*/
#endif

/** widget from mdi area activated */
void DCConnectionManager::slotMdiSubWindowActivated( QMdiSubWindow * w )
{
        if (!w)
            return;

        QMapIterator<QWidget*, int> it(windowsList);
        QWidget *wgt = (QWidget*)w;
        QWidget *mdi_wgt = w->widget();

        while (it.hasNext()){
            it.next();
            if ((it.key() == wgt) || (it.key() == mdi_wgt)){
                m_nSelectedTab = it.value();
                m_pTabBar->setCurrentIndex( m_nSelectedTab );
                m_pTabBar->setTabIcon(m_nSelectedTab, QIcon() );
                return;
            }
        }
}

/** */
void DCConnectionManager::HubEvent( DCClient * client )
{
	if ( !client )
		return;
	
        int i = windowsList[(QWidget*)client->GetMdiSubWindow()];

	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 = windowsList[(QWidget*)client->GetMdiSubWindow()];
		
		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 )
{
        if ( m_pTabBar->count() == 0 )
        {
                m_pTabBar->hide();
        }

        disconnect(client, SIGNAL(onDie(QWidget*)), g_pMainWin, SLOT(slotChildOnDie(QWidget*)));

        RemoveHub( client );
}

/** 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.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();
	
        connect(client, SIGNAL(onDie(QWidget*)), g_pMainWin, SLOT(slotChildOnDie(QWidget*)));
        addTab((QWidget*)client->GetMdiSubWindow(), QString::fromAscii(hubname.Data()));

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

	switch ( g_pConfig->GetOpenClientWindows() )
	{
		case eClientMinimized:
                        client->showMinimized();
			break;
		case eClientMaximized:
                        client->showMaximized();
                        client->GetMdiSubWindow()->showMaximized();
		// update tabbar
                        slotMdiSubWindowActivated(client->GetMdiSubWindow());
			break;
		case eClientNormal:
		default:
                        client->show();
                        client->GetMdiSubWindow()->show();
                        client->centreOnMdiArea();
		// update tabbar
                        slotMdiSubWindowActivated(client->GetMdiSubWindow());
			break;
	}

	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::CloseAllTabs()
{
    windowsList.clear();

    while (m_pTabBar->count() > 0){
	m_pTabBar->removeTab(0);
    }
}

/** */
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 ));
}


void DCConnectionManager::addTab(QWidget *wgt, QString name)
{
    if (!wgt || name == "")
        return;
    if (windowsList.contains(wgt) && (windowsList[wgt] != -1))
        return;

    if (name.length() > 20)
        name = name.left(20) + "...";

    const int i = m_pTabBar->addTab(wgt->windowIcon(), name);

    windowsList[wgt] = i;
    m_pTabBar->setCurrentIndex(i);

}

void DCConnectionManager::remTab(QWidget *wgt, bool disc, QWidget *par)
{
    if (!wgt || !windowsList.contains(wgt))
        return;

    QList<int> list = windowsList.values();
    int i = windowsList.take(wgt);
    m_pTabBar->removeTab(i);

    qSort(list.begin(), list.end());

    int index = list.indexOf(i);
    index++;

    for (; index < list.count(); index++){
        QWidget *t = windowsList.key(list.at(index));
        windowsList[t] = list.at(index)-1;
    }

    if (disc){
        if (!disconnect(wgt, SIGNAL(onDie(QWidget*)), par, SLOT(slotChildOnDie(QWidget*)))){
            QMdiSubWindow *mdi_wind;

            try{
                mdi_wind = dynamic_cast<QMdiSubWindow*>(wgt);
            }
            catch (std::exception &e){
                std::cout << e.what() << std::endl;
                return;
            }

            if (!mdi_wind)
                return;

            QWidget *sig_sender = mdi_wind->widget();

            disconnect(sig_sender, SIGNAL(onDie(QWidget*)), par, SLOT(slotChildOnDie(QWidget*)));
        }
    }
}

QWidget *DCConnectionManager::GetWidgetForTab( int tab ) const
{
    if (tab < 0 || tab > (m_pTabBar->count() - 1))
        return NULL;

    QMapIterator<QWidget*, int> it(windowsList);
    QWidget *wgt = NULL;

    while (it.hasNext()){
        it.next();
        if (it.value() == tab){

            wgt = it.key();

            return wgt;
        }
    }

    return wgt;
}

void DCConnectionManager::repaintTabbarIcons()
{
    QMapIterator<QWidget*, int> it(windowsList);

    m_pTabBar->drawBase();

    while (it.hasNext()){
        it.next();

        m_pTabBar->setTabIcon(it.value(), it.key()->windowIcon());
    }
}

#ifdef QT_NEW
/*
void DCConnectionManager::slotCloseTabButtonClicked(int index)
{
    QWidget *wgt = GetWidgetForTab(index);

    if (wgt)
        wgt->close();

}
*/
#endif
