#ifndef _KVI_CONSOLE_H_
#define _KVI_CONSOLE_H_
//=============================================================================
//
//   File : kvi_console.h
//   Creation date : Sun Jun 25 2000 15:00:20 by Szymon Stefanek
//
//   This file is part of the KVirc irc client distribution
//   Copyright (C) 1999-2000 Szymon Stefanek (pragma at kvirc dot net)
//
//   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 opinion) any later version.
//
//   This program is distributed in the HOPE that it will be USEFUL,
//   but WITHOUT ANY WARRANTY; without even the implied warranty of
//   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
//   See the GNU General Public License for more details.
//
//   You should have received a copy of the GNU General Public License
//   along with this program. If not, write to the Free Software Foundation,
//   Inc. ,59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
//=============================================================================

#include "kvi_settings.h"
#include "kvi_window.h"
#include "kvi_irclink.h"
#include "kvi_string.h"
#include "kvi_lagmeter.h"
#include "kvi_wstring.h"
#include "kvi_irccontext.h"

#include "kvi_list.h"

#include <time.h>

class QToolBar;
class QToolButton;

class KviAvatar;
class KviDns;
class KviIrcUserDataBase;
class KviIrcUserEntry;
class KviIrcServer;
class KviIrcNetwork;
class KviProxy;
#ifndef COMPILE_ON_WINDOWS
	class KviChannel;
	class KviQuery;
#else
	// windoze wants it to compile QList<KviChannel> and QList<KviQuery>
	#include "kvi_channel.h"
	#include "kvi_query.h"
#endif
class KviUserListView;
class KviNotifyListManager;
//class KviIrcContextController;
class KviRegisteredUser;
class KviLagMeter;

typedef struct _KviWhoisInfo
{
	KviStr szNick;
	KviStr szUser;
	KviStr szHost;
	KviStr szReal;
	KviStr szServer;
	KviStr szIdle;
	KviStr szSignon;
	KviStr szChannels;
	KviStr szSpecial;
	KviStr szCode;
	KviStr szMagic;
	KviWindow * pWindow;
} KviWhoisInfo;



class KviConnectionInfo
{
public:
	KviConnectionInfo(KviIrcNetwork * net,KviIrcServer * srv,KviProxy * prx);
	~KviConnectionInfo();
public:
	KviStr                        szNetworkName;              // selected at connect time
	KviIrcServer                * pIrcServer;                 // current irc server (local copy) (never 0)
	KviProxy                    * pProxy;                     // current proxy (local copy if non 0)
	KviStr                        szBindAddress;              // address to bind the local machine to
	time_t                        tConnectionStart;           // time when the connection started (valid only when Connected or LoggingIn)
	time_t                        tLastMessage;               // time of the last message from server (valid only when Connected or LoggingIn)
	bool                          bSentQuit;                  // sent the quit message ?
	KviDns                      * pDns;                       // non 0 if resolving a host
	int                           iNicknameUsed;              // loginToIrcServer()
	KviStr                        szLocalHostIp;              // resolveLocalHost()
	KviIrcUserDataBase          * pUserDataBase;              // local user database
	KviNotifyListManager        * pNotifyListManager;         // restartNotifyList()
	KviStr                        szRealName;                 // the one sent to the server at login
	KviStr                        szNickName;                 // the current one
	KviStr                        szUserMode;                 // the current one
	KviStr                        szLocalHostFromServer;      // local host from server
	KviStr                        szLocalIpFromServer;        // our IP as seen by the irc server: may be empty (hidden IP or not resolved yet)
	KviStr                        szUserNameFromServer;       // username from server (with ident chars)
	KviStr                        szServerNameFromServer;     // the server wants to be known as
	KviStr                        szServerSupportedUserModes;
	KviStr                        szServerSupportedChanModes;
	KviStr                        szServerSupportedModePrefixes;
	KviStr                        szServerSupportedChanTypes;
	KviStr                        szCommandToExecAfterConnect;
	bool                          bServerSupportsModeIe;
	bool                          bServerSupportsWatchList;

	QTimer                      * pNotifyListTimer;           // delayed startup timer for the notify lists

	KviPtrList<KviChannel>      * pChannelList;
	KviPtrList<KviQuery>        * pQueryList;

	KviStr                        szLastNetsplit;
	time_t                        lastNetsplitTime;

	KviPtrList<KviWhoisInfo>    * pWhoisInfoList;             // awhois pending stuff

	time_t                        lastCtcpTime;
	unsigned int                  uCtcpCount;

	bool                          bAway;
	time_t                        tAwayTime;
	KviStr                        szNickBeforeAway;
	
	KviDns                      * pLocalhostDns;              // this is used to resolve the localhost
public:
	KviChannel                  * findChannel(const char * name);
	KviQuery                    * findQuery(const char * nick);
	KviIrcUserDataBase          * userDataBase(){ return pUserDataBase; };

};

typedef struct KviAsyncServerCommandData
{
	KviStr             szServer;
	unsigned short int uPort;
	bool               bPortIsOk;
	bool               bUseIpV6;
	bool               bUseSSL;
	KviStr             szBindAddress; // ip address (or interface name) to bind the connection to
	KviStr             szCommandToExecAfterConnect;
	KviStr             szLinkFilter;
	KviStr             szPass;
	KviStr             szNick;
    KviStr             szInitUMode;
} KviAsyncServerCommandData;

//=================================================================================================
//
// The console window
//
//=================================================================================================

#define KVI_CONSOLE_FLAG_FIRSTINAPP 1
#define KVI_CONSOLE_FLAG_FIRSTINFRAME 2

class KVIRC_API KviConsole : public KviWindow
{
	friend class KviFrame;
	friend class KviIrcLink;
	friend class KviChannel;
	friend class KviQuery;
	friend class KviIrcLinkMonitor;
	Q_OBJECT
public:
	enum ConnectionState { Connecting , LoggingIn , Connected , NotConnected };
protected:
	KviConsole(KviFrame * lpFrm,int iFlags);
public:
	~KviConsole();
protected:
	int                                m_iFlags; // FIXME: make this a KviWindow property ?
	unsigned int                       m_uConnectAttemptCount;

//	KviConnection                    * m_pConnection;
	KviIrcLink                       * m_pLink;
	KviPtrList<KviIrcLinkMonitor>    * m_pMonitorList;
	KviConnectionInfo                * m_pConnectionInfo;
	ConnectionState                    m_state;
	// This stuff is used for the SERVER command
	KviAsyncServerCommandData        * m_pAsyncServerCommandData;
	// the last irc server that this console connected to: it is a copy!
	KviIrcServer                     * m_pLastIrcServer;
	KviLagMeter                      * m_pLagMeter;

	// UI
	KviUserListView                  * m_pNotifyListView;
	QToolButton                      * m_pNotifyViewButton;
	QString                            m_szStatusString; // nick (flags) on server | not connected
protected:
	// UI
	virtual QPixmap * myIconPtr();
	virtual void fillCaptionBuffers();
	virtual void resizeEvent(QResizeEvent *e);
	virtual void closeEvent(QCloseEvent *e);
	virtual void getBaseLogFileName(KviStr &buffer);
	virtual void getTaskBarTipText(QString &buffer);
	virtual void fillContextPopup(QPopupMenu * p);
	virtual QSize sizeHint() const;
	virtual void applyOptions();
	virtual void triggerCreationEvents();

	void createLink(const KviStr &szLinkFilterName);
	void destroyLink();

	void fillStatusString();
	void linkEvent(KviIrcLink::LinkEvent ev,void * arg);
	void registerLinkMonitor(KviIrcLinkMonitor * m);
	void unregisterLinkMonitor(KviIrcLinkMonitor * m);
	void setChannelAsDead(KviChannel * c);
	void setQueryAsDead(KviQuery * q);
	void setChannelAsAlive(KviChannel * c);
	void setQueryAsAlive(KviQuery * q);
	
//	void createConnectionInfo(KviIrcNetwork * net,KviIrcServer * srv,KviProxy * prx);
	void keepChannelsOpenAfterDisconnect();
	void keepQueriesOpenAfterDisconnect();
	void resurrectDeadQueries();
	void destroyConnection();
	void destroyAsyncServerCommandData();
	void haveServerIp();
	void lookupServerHostname();
	void lookupProxyHostname();
	void setState(ConnectionState st);
	void resolveLocalHost();
	void loginToIrcServer();
	void registerQuery(KviQuery *q);
	void registerChannel(KviChannel *c);
	void unregisterQuery(KviQuery *q);
	void unregisterChannel(KviChannel *c);
	void startNotifyList();
//	void destroyDnsObject(KviDns * d);
//	void triggerCreationEvents(bool bTriggerOnFrameCreated = false);
	bool validateLocalAddress(const char * szAddress,KviStr &szBuffer);
public:
	// this is called by KviIrcLink when a message is arriving from the server
	void incomingMessage(const char * message);

	//
	// State
	//
	KviConsole::ConnectionState state(){ return m_state; };
	KviIrcContext * ircContext(){ return m_pIrcContext; };
	unsigned int ircContextId(){ return m_pIrcContext->id(); };
	KviConnectionInfo * connection(){ return m_pConnectionInfo; };
	//
	// Sock state
	//
	KviIrcLink * link(){ return m_pLink; };
	bool isConnected(){ return (m_state == Connected); };
	bool isIpV6Connection();
	bool isNotConnected(){ return (m_state == NotConnected); };
	bool connectionInProgress(){ return ((m_state != NotConnected) || (m_pAsyncServerCommandData != 0)); };
	//
	// Socket monitors
	//
//	KviPtrList<KviIrcLinkMonitor> * ircSocketMonitors(){ return m_pServerLinkMonitorList; };
//	void registerSocketMonitor(KviIrcLinkMonitor * m);
//	void unregisterSocketMonitor(KviIrcLinkMonitor *m);
	//
	// This connection info
	//
	KviConnectionInfo * connectionInfo(){ return m_pConnectionInfo; };
	const char * currentNickName(){ return (m_pConnectionInfo ? m_pConnectionInfo->szNickName.ptr() : KviStr::emptyString().ptr()); };
	const char * currentUserName(){ return (m_pConnectionInfo ? m_pConnectionInfo->szUserNameFromServer.ptr() : KviStr::emptyString().ptr()); };
	const char * currentUserMode(){ return (m_pConnectionInfo ? m_pConnectionInfo->szUserMode.ptr() : KviStr::emptyString().ptr()); };
	const char * currentLocalHostName(){ return (m_pConnectionInfo ? m_pConnectionInfo->szLocalHostFromServer.ptr() : KviStr::emptyString().ptr()); };
	const char * currentLocalHostIp(){ return (m_pConnectionInfo ? m_pConnectionInfo->szLocalIpFromServer.ptr() : KviStr::emptyString().ptr()); };
	const char * currentServerName(){ return (m_pConnectionInfo ? m_pConnectionInfo->szServerNameFromServer.ptr() : KviStr::emptyString().ptr()); };
	const char * currentNetworkName(){ return (m_pConnectionInfo ? m_pConnectionInfo->szNetworkName.ptr() : KviStr::emptyString().ptr()); };
	KviAvatar * currentAvatar();
	//
	// UI internals
	//
	virtual void loadProperties(KviConfig * cfg);
	virtual void saveProperties(KviConfig * cfg);
	KviUserListView * notifyListView(){ return m_pNotifyListView; };
	//
	// IRC Context wide helpers (connection related)
	//
	int getCommonChannels(const char * nick,KviStr &chansBuffer,bool bEscapeSeq = true);
	void getUserTipText(const char * nick,KviIrcUserEntry *e,QString &buffer);
	void outputPrivmsg(KviWindow *wnd,int type,const char *nick,
		const char *user,const char *host,const char *msg,bool bApplyHighlighting = true);
	// Avatar helpers (conneciton related)
	void resetAvatarForMatchingUsers(KviRegisteredUser * u);
	// this should be protected at least
	void avatarChangedUpdateWindows(const char * nick,const char * textLine);
	void avatarChanged(KviAvatar * avatar,const char * nick,const char * user,const char * host,const char * textLine);
	KviAvatar * setAvatar(const char * nick,const char * user,const char * host,const char * fName);
	void checkDefaultAvatar(KviIrcUserEntry *e,const char * nick,const char *user,const char * host);
	
	// This returns the default avatar for the current KVIrc user
	// if he has choosen a valid avatar in the options dialog
	// otherwise returns 0.
	// The avatar is allocated with new and must be deleted
	// when no longer needed.
	KviAvatar * defaultAvatarFromOptions();
	
	// Away (connection related)
	void changeAwayState(bool bAway);
	bool userIsAway(){ return m_pConnectionInfo ? m_pConnectionInfo->bAway : false; };
	// Async whois stuff (Connection related)
	void addAsyncWhois(KviWhoisInfo * i){ m_pConnectionInfo->pWhoisInfoList->append(i); };
	KviWhoisInfo * lookupAsyncWhois(const char * nick);
	void removeAsyncWhois(KviWhoisInfo * i){ m_pConnectionInfo->pWhoisInfoList->removeRef(i); };

	void setAsyncServerCommandData(KviAsyncServerCommandData * d);
	void connectToCurrentServer();
	void loginComplete(const char * servNick);
	void terminateConnectionRequest(bool bForce = false,const char * quitMsg = 0);

	// User mode (connection related)
	bool hasUserMode(char c){ return (m_pConnectionInfo ? m_pConnectionInfo->szUserMode.contains(c) : false); };
	bool userModeEmpty(){ return (m_pConnectionInfo ? m_pConnectionInfo->szUserMode.isEmpty() : true); };
	bool setUserMode(char mode,bool bSet);
	// Status string (usermode + nick) (connection related too)
	const QString & statusString(){ return m_szStatusString; };
	// Channel and query window managements (connection related)
	KviQuery * createQuery(const char * name);
	KviChannel * createChannel(const char * name);
	KviPtrList<KviChannel> * channelList(){ return m_pConnectionInfo ? m_pConnectionInfo->pChannelList : 0; };
	KviPtrList<KviQuery> * queryList(){ return m_pConnectionInfo ? m_pConnectionInfo->pQueryList : 0; };
	unsigned int channelCount(){ return (m_pConnectionInfo ? m_pConnectionInfo->pChannelList->count() : 0); };
	unsigned int queryCount(){ return (m_pConnectionInfo ? m_pConnectionInfo->pQueryList->count() : 0); };
	// Window management
	KviChannel * findChannel(const char * name){ return connection() ? connection()->findChannel(name) : 0; };
	KviQuery * findQuery(const char * nick){ return connection() ? connection()->findQuery(nick) : 0; };
	KviQuery * findQueryByName(const char * nick);
	KviWindow * activeWindow();
	// User db, connection related
	KviIrcUserDataBase * userDataBase(){ return m_pConnectionInfo ? m_pConnectionInfo->pUserDataBase : 0; };
	void setUserInfoFromServer(const char * username,const char *localhost);
	void setServerInfoFromServer(const char * servname,const char * umodes,const char * chanmodes);
	void nickChange(const char * newNick);
	void completeChannel(const KviStr &word,KviPtrList<KviStr> * matches);
	void completeServer(const KviStr &word,KviPtrList<KviStr> * matches);
	// Monitors
	bool hasMonitors(){ return m_pMonitorList != 0; };
	KviPtrList<KviIrcLinkMonitor> * monitorList(){ return m_pMonitorList; };
    KviLagMeter * lagMeter(){ return m_pLagMeter; };

public slots:
	void restartNotifyList();
	void asyncServerCommand();
	void executeInternalCommand(int index);
	void connectButtonClicked();
protected slots:
	void linkDestroyed();
	void toggleNotifyView();
	void textViewRightClicked();
	void localHostLookupTerminated(KviDns *);
	void serverLookupTerminated(KviDns *);
	void proxyLookupTerminated(KviDns *);
	void closeAllChannels();
	void closeAllQueries();
	void partAllChannels();
signals:
	void stateChange(KviConsole::ConnectionState newState);
};

#endif //_KVI_CONSOLE_H_
