//
// This file is part of the aMule Project.
//
// Copyright (c) 2003-2009 aMule Team ( admin@amule.org / http://www.amule.org )
// Copyright (c) 2002 Merkur ( devs@emule-project.net / http://www.emule-project.net )
//
// Any parts of this program derived from the xMule, lMule or eMule project,
// or contributed by third-party developers are copyrighted by their
// respective authors.
//
// 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.
//
// 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA
//


#ifndef AMULE_H
#define AMULE_H


#include <wx/app.h>		// Needed for wxApp
#include <wx/intl.h>		// Needed for wxLocale

// ADUNANZA BEGIN
#include "KADUSettings.h"
// ADUNANZA END

#include "Types.h"		// Needed for int32, uint16 and uint64

// ADUNANZA BEGIN
// Per wxWidgets 2.9.x e Snow Leopard
#if 0


#ifndef __WXMSW__
	#include <map>
	#include <signal.h>
	#include <wx/unix/execute.h>
#endif // __WXMSW__



#else

#include <map>
#ifndef __WXMSW__
	#include <signal.h>
//	#include <wx/unix/execute.h>
#endif // __WXMSW__


#endif
// ADUNANZA END


class CAbstractFile;
class CKnownFile;
class ExternalConn;
class CamuleDlg;
class CPreferences;
class CDownloadQueue;
class CUploadQueue;
class CServerConnect;
class CSharedFileList;
class CServer;
class CFriend;
class CMD4Hash;
class CServerList;
class CListenSocket;
class CClientList;
class CKnownFileList;
class CSearchList;
class CClientCreditsList;
class CFriendList;
class CClientUDPSocket;
class CIPFilter;
class UploadBandwidthThrottler;
#ifdef ENABLE_UPNP
class CUPnPControlPoint;
class CUPnPPortMapping;
#endif
class CStatistics;
class wxSocketEvent;
class wxCommandEvent;
class wxFFileOutputStream;
class CUpDownClient;
class CTimer;
class CTimerEvent;
class wxSingleInstanceChecker;
class CHashingEvent;
class CMuleInternalEvent;
class CCompletionEvent;
class CAllocFinishedEvent;
class wxExecuteData;
class CLoggingEvent;

// ADUNANZA BEGIN
// Se non metto wxCloseEvent la patch Adunanza non compila
// (novita' delle versioni di Dicembre, forse dipende dai
// cambiamenti nei flag dei makefile e dall'ordine degli include)
class wxCloseEvent;

class CRemoteSettings;
class wxFileConfig;

class CAduUploadSlotsManager; // Mr Hyde

// ADUNANZA END


namespace MuleNotify {
	class CMuleGUIEvent;
}


using MuleNotify::CMuleGUIEvent;


#ifdef AMULE_DAEMON
#define AMULE_APP_BASE wxAppConsole
#define CORE_TIMER_PERIOD 300
#else
#define AMULE_APP_BASE wxApp
#define CORE_TIMER_PERIOD 100
#endif

#define CONNECTED_ED2K (1<<0)
#define CONNECTED_KAD_NOT (1<<1)
#define CONNECTED_KAD_OK (1<<2)
#define CONNECTED_KAD_FIREWALLED (1<<3)


class CamuleApp : public AMULE_APP_BASE
{
private:
	enum APPState {
		APP_STATE_RUNNING = 0,
		APP_STATE_SHUTTINGDOWN,
		APP_STATE_STARTING
	};

public:
	CamuleApp();
	virtual	 ~CamuleApp();

	virtual bool	OnInit();
	int		OnExit();
	void		OnFatalException();
	bool		ReinitializeNetwork(wxString *msg);

	// derived classes may override those
	virtual int InitGui(bool geometry_enable, wxString &geometry_string);

	// Socket handlers
	void ListenSocketHandler(wxSocketEvent& event);
	void ServerSocketHandler(wxSocketEvent& event);
	void UDPSocketHandler(wxSocketEvent& event);

	virtual void ShowAlert(wxString msg, wxString title, int flags) = 0;

	// Barry - To find out if app is running or shutting/shut down
	bool IsRunning() const { return (m_app_state == APP_STATE_RUNNING); }
	bool IsOnShutDown() const { return (m_app_state == APP_STATE_SHUTTINGDOWN); }

	// Check ED2K and Kademlia state
	bool IsFirewalled();
	// Check Kad state
	bool IsFirewalledKad();
	// Check if we should callback this client
	bool DoCallback( CUpDownClient *client );

	// Connection to ED2K
	bool IsConnectedED2K();
	// Connection to Kad
	bool IsConnectedKad();
	// Are we connected to at least one network?
	bool IsConnected();

	// What about Kad? Is it running?
	bool IsKadRunning();

	// URL functions
	wxString	CreateMagnetLink(const CAbstractFile *f);
	wxString	CreateED2kLink(const CAbstractFile* f, bool add_source = false, bool use_hostname = false, bool addcryptoptions = false);	
	wxString	CreateED2kAICHLink(const CKnownFile* f);

	// Misc functions
	void		OnlineSig(bool zero = false);
	void		Localize_mule();
	void		Trigger_New_version(wxString newMule);

	// shakraw - new EC code using wxSocketBase
	ExternalConn*	ECServerHandler;

	// return current (valid) public IP or 0 if unknown
	// If ignorelocal is true, don't use m_localip
	uint32	GetPublicIP(bool ignorelocal = false) const; 
	void		SetPublicIP(const uint32 dwIP);
	
	uint32	GetED2KID() const;
	uint32	GetID() const;	

	// Other parts of the interface and such
	CPreferences*		glob_prefs;
	CDownloadQueue*		downloadqueue;
	CUploadQueue*		uploadqueue;
	CServerConnect*		serverconnect;
	CSharedFileList*	sharedfiles;
	CServerList*		serverlist;
	CListenSocket*		listensocket;
	CClientList*		clientlist;
	CKnownFileList*		knownfiles;
	CSearchList*		searchlist;
	CClientCreditsList*	clientcredits;
	CFriendList*		friendlist;
	CClientUDPSocket*	clientudp;
	CStatistics*		m_statistics;
	CIPFilter*		ipfilter;
	UploadBandwidthThrottler* uploadBandwidthThrottler;
#ifdef ENABLE_UPNP
	CUPnPControlPoint*	m_upnp;
	std::vector<CUPnPPortMapping> m_upnpMappings;
#endif
	wxLocale m_locale;

// ADUNANZA BEGIN
        bool                    m_bValidRemoteSettings;
#if !defined(CLIENT_GUI)
	CRemoteSettings*        rm;
#endif	
	wxFileConfig*           acfg;
	CAduUploadSlotsManager* pUploadSlotsMng;

	CKADUSettings           m_KADUSettings;
	wxMutex			m_mutexKADUSettings; // per proteggere la scrittura su m_KADUSettings

#if !defined(CLIENT_GUI)
        inline CRemoteSettings* getRemoteSettings() {return ((m_bValidRemoteSettings && rm) ? rm : 0);}
        inline const CRemoteSettings* getRemoteSettings() const {return ((m_bValidRemoteSettings && rm) ? rm : 0);}
#endif	

	inline const CKADUSettings& getKADUSettings() const {return m_KADUSettings;}

	inline long          get_kadRepublishTimeK() const {return m_KADUSettings.m_kadRepublishTimeK;}
	inline long          get_kadRepublishTimeS() const {return m_KADUSettings.m_kadRepublishTimeS;}
	inline long          get_kadRepublishTimeN() const {return m_KADUSettings.m_kadRepublishTimeN;}

	inline long          get_kadIndexLifeK() const {return m_KADUSettings.m_kadIndexLifeK;}
	inline long          get_kadIndexLifeS() const {return m_KADUSettings.m_kadIndexLifeS;}

	inline uint32_t      get_kadTotalStoreKey()   const {return m_KADUSettings.m_kadTotalStoreKey;}
	inline uint32_t      get_kadTotalStoreSrc()   const {return m_KADUSettings.m_kadTotalStoreSrc;}
	inline uint32_t      get_kadTotalStoreNotes() const {return m_KADUSettings.m_kadTotalStoreNotes;}

	inline long          get_kadTotalSearchFile() const {return m_KADUSettings.m_kadTotalSearchFile;}

	inline long          get_kadMaxSrcFile() const {return m_KADUSettings.m_kadMaxSrcFile;}
	inline long          get_kadMaxNotFile() const {return m_KADUSettings.m_kadMaxNotFile;}

	inline double        get_kadFreshGuess_Tol()     const {return m_KADUSettings.m_kadFreshGuess_Tol;}
	inline double        get_kadFreshGuess_Weight()  const {return m_KADUSettings.m_kadFreshGuess_Weight;}
	inline long          get_kadFreshGuess_NoNorm()  const {return m_KADUSettings.m_kadFreshGuess_NoNorm;}
	inline long          get_kadFreshGuess_LowNorm() const {return m_KADUSettings.m_kadFreshGuess_LowNorm;}

	inline long          get_kadFindValue() const {return m_KADUSettings.m_kadFindValue;}
	inline long          get_kadStore()     const {return m_KADUSettings.m_kadStore;}
	inline long          get_kadFindNode()  const {return m_KADUSettings.m_kadFindNode;}

	inline long          get_kadReaskTime() const {return m_KADUSettings.m_kadReaskTime;}
	inline long          get_kadPubTime()   const {return m_KADUSettings.m_kadPubTime;}

	inline long          get_kadReaskIncs() const {return m_KADUSettings.m_kadReaskIncs;}

	inline long          get_mVer() const {return m_KADUSettings.m_mVer;}

	inline unsigned char get_kadOpcode()  const {return m_KADUSettings.m_kadOpcode;}
	inline unsigned char get_kadZOpcode() const {return m_KADUSettings.m_kadZOpcode;}
	
// ADUNANZA END
	
	void ShutDown();

	wxString GetLog(bool reset = false);
	wxString GetServerLog(bool reset = false);
	wxString GetDebugLog(bool reset = false);

	bool AddServer(CServer *srv, bool fromUser = false);
	void AddServerMessageLine(wxString &msg);
#ifdef __DEBUG__
	void AddSocketDeleteDebug(uint32 socket_pointer, uint32 creation_time);
#endif
	void SetOSFiles(const wxString new_path);

	wxString ConfigDir;

	void AddLogLine(const wxString &msg);

	const wxString& GetOSType() const { return OSType; }

	void ShowUserCount();

	void ShowConnectionState();

// ADUNANZA BEGIN
	bool PreStartKad(); // Mr Hyde
// ADUNANZA END
	void StartKad();
	void StopKad();

	/** Bootstraps kad from the specified IP (must be in hostorder). */
	void BootstrapKad(uint32 ip, uint16 port);
	/** Updates the nodes.dat file from the specified url. */
	void UpdateNotesDat(const wxString& str);


	void DisconnectED2K();
	
	bool CryptoAvailable() const;
	
	//! TODO: Move to CLogger
	wxFFileOutputStream* applog;
protected:
	// Used to detect a previous running instance of aMule
	wxSingleInstanceChecker*	m_singleInstance;
	
#ifdef __WXDEBUG__
	/**
	 * Handles asserts in a thread-safe manner.
	 */
	virtual void OnAssertFailure(const wxChar* file, int line,
		const wxChar* func, const wxChar* cond, const wxChar* msg);
#endif

	/**
	 * This class is used to contain log messages that are to be displayed
	 * on the GUI, when it is currently impossible to do so. This is in order
	 * to allows us to queue messages till after the dialog has been created.
	 */
	struct QueuedLogLine
	{
		//! The text line to be displayed
		wxString 	line;
		//! True if the line should be shown on the status bar, false otherwise.
		bool		show;
	};

	void OnUDPDnsDone(CMuleInternalEvent& evt);
	void OnSourceDnsDone(CMuleInternalEvent& evt);
	void OnServerDnsDone(CMuleInternalEvent& evt);

	void OnTCPTimer(CTimerEvent& evt);
	void OnCoreTimer(CTimerEvent& evt);

	void OnFinishedHashing(CHashingEvent& evt);
	void OnFinishedAICHHashing(CHashingEvent& evt);
	void OnFinishedCompletion(CCompletionEvent& evt);
	void OnFinishedAllocation(CAllocFinishedEvent& evt);
	void OnFinishedHTTPDownload(CMuleInternalEvent& evt);
	void OnHashingShutdown(CMuleInternalEvent&);
	void OnNotifyEvent(CMuleGUIEvent& evt);

	void SetTimeOnTransfer();

	std::list<QueuedLogLine> m_logLines;

	APPState m_app_state;

	wxString m_emulesig_path;
	wxString m_amulesig_path;

	char *strFullMuleVersion;
	char *strOSDescription;
	wxString OSType;

	uint32 m_dwPublicIP;

	long webserver_pid;

	bool enable_stdout_log;
	bool enable_daemon_fork;
// ADUNANZA BEGIN
// Backport per PID
	wxString PidFile;
// ADUNANZA END
	wxString server_msg;

	CTimer* core_timer;

private:
	virtual void OnUnhandledException();

	void CheckNewVersion(uint32 result);

	uint32 m_localip;
};


#ifndef AMULE_DAEMON


class CamuleGuiBase {
public:
	CamuleGuiBase();
	virtual	 ~CamuleGuiBase();

	wxString	m_FrameTitle;
	CamuleDlg*	amuledlg;
	int m_FileDetailDialogActive;

	bool CopyTextToClipboard( wxString strText );

	virtual int InitGui(bool geometry_enable, wxString &geometry_string);
	virtual void ShowAlert(wxString msg, wxString title, int flags);
};


#ifndef CLIENT_GUI


class CamuleGuiApp : public CamuleApp, public CamuleGuiBase
{

    virtual int InitGui(bool geometry_enable, wxString &geometry_string);

	int OnExit();
	bool OnInit();
	
public:

	virtual void ShowAlert(wxString msg, wxString title, int flags);

	void ShutDown(wxCloseEvent &evt);
	void OnLoggingEvent(CLoggingEvent& evt);

	wxString GetLog(bool reset = false);
	wxString GetServerLog(bool reset = false);
	void AddServerMessageLine(wxString &msg);
	DECLARE_EVENT_TABLE()
};


DECLARE_APP(CamuleGuiApp)
#ifdef AMULE_CPP
	CamuleGuiApp *theApp;
#else
	extern CamuleGuiApp *theApp;
#endif


#else /* !CLIENT_GUI */


#include "amule-remote-gui.h"


#endif // CLIENT_GUI


#define CALL_APP_DATA_LOCK


#else /* ! AMULE_DAEMON */

// ADUNANZA BEGIN
// Backport da aMule 2.3.x SVN per wxWidgets 2.9.x e Snow Leopard
//
// #include <wx/apptrait.h> COMMENTATA PER PATCH ADUNANZA
// #include <wx/socket.h>   COMMENTATA PER PATCH ADUNANZA
//
//
// wxWidgets 2.8 requires special code for event handling and sockets.
// 2.9 doesn't, so standard event loop and sockets can be used
//
// Windows: aMuled compiles with 2.8 (without the special code), 
// but works only with 2.9

#if !wxCHECK_VERSION(2, 9, 0)
	#ifdef __WXMSW__
		// MSW: can't run amuled with 2.8 anyway, just get it compiled
		#define AMULED_DUMMY
	#else
		#define AMULED28
	#endif
#endif

#ifdef AMULED28
#include <wx/socket.h>

// ADUNANZA BEGIN
// Test per GSocket (copiato da src di wxWidgets. gtk/gsockgtk.cpp) per GLIB >= 2.21
// newer versions of glib define its own GSocket but we unfortunately use this
// name in our own (semi-)public header and so can't change it -- rename glib
// one instead
// #define GSocket GlibGSocket
// #include <gdk/gdk.h>
// #include <glib.h>
// #undef GSocket

#include "wx/gsocket.h"
#include "wx/unix/gsockunx.h"
// ADUNANZA END
	
	
// ADUNANZA END


class CSocketSet;


class CAmuledGSocketFuncTable : public GSocketGUIFunctionsTable
{
private:
	CSocketSet *m_in_set, *m_out_set;

	wxMutex m_lock;
public:
	CAmuledGSocketFuncTable();

	void AddSocket(GSocket *socket, GSocketEvent event);
	void RemoveSocket(GSocket *socket, GSocketEvent event);
	void RunSelect();

	virtual bool OnInit();
	virtual void OnExit();
	virtual bool CanUseEventLoop();
	virtual bool Init_Socket(GSocket *socket);
	virtual void Destroy_Socket(GSocket *socket);
	virtual void Install_Callback(GSocket *socket, GSocketEvent event);
	virtual void Uninstall_Callback(GSocket *socket, GSocketEvent event);
	virtual void Enable_Events(GSocket *socket);
	virtual void Disable_Events(GSocket *socket);
};

// ADUNANZA BEGIN
// Sempre per wx 2.9.x e Snow Leopard
//
// typedef std::map<int, wxEndProcessData *> EndProcessDataMap;  COMMENTATA PER PATCH ADUNANZA

#endif // AMULED28

// no AppTraits used on Windows
#ifndef __WXMSW__

typedef std::map<int, class wxEndProcessData *> EndProcessDataMap;

#include <wx/apptrait.h>
// ADUNANZA END


class CDaemonAppTraits : public wxConsoleAppTraits
{
private:
// ADUNANZA BEGIN
// Per wx 2.9.x e Snow Leopard
//
// 	CAmuledGSocketFuncTable *m_table; COMMENTATA PER ADUNANZA
// 	wxMutex m_lock; COMMENTATA PER ADUNANZA
// 	std::list<wxObject *> m_sched_delete; COMMENTATA PER ADUNANZA
// #ifndef __WXMSW__ COMMENTATA PER ADUNANZA
// 	struct sigaction m_oldSignalChildAction; COMMENTATA PER ADUNANZA
// 	struct sigaction m_newSignalChildAction; COMMENTATA PER ADUNANZA
// #endif COMMENTATA PER ADUNANZA
//
	struct sigaction m_oldSignalChildAction;
	struct sigaction m_newSignalChildAction;

#ifdef AMULED28
	CAmuledGSocketFuncTable *m_table;
	wxMutex m_lock;
	std::list<wxObject *> m_sched_delete;
// ADUNANZA END

public:
	CDaemonAppTraits(CAmuledGSocketFuncTable *table);
	virtual GSocketGUIFunctionsTable* GetSocketGUIFunctionsTable();
	virtual void ScheduleForDestroy(wxObject *object);
	virtual void RemoveFromPendingDelete(wxObject *object);

	void DeletePending();

// ADUNANZA BEGIN
// Per wx 2.9.x e Snow Leopard
//
// #ifndef __WXMSW__ COMMENTATA PER ADUNANZA
// 	virtual int WaitForChild(wxExecuteData& execData); COMMENTATA PER ADUNANZA
// #endif COMMENTATA PER ADUNANZA

#else	// AMULED28
public:
	CDaemonAppTraits();
#endif	// !AMULED28
	virtual int WaitForChild(wxExecuteData& execData);
// ADUNANZA END

// ADUNANZA BEGIN
// Per wxWidgets 2.9.x e Snow Leopard
#if 0

#ifdef __WXMAC__
	virtual wxStandardPathsBase& GetStandardPaths();
#endif


#else

#if defined(__WXMAC__) && !wxCHECK_VERSION(2, 9, 0)
	virtual wxStandardPathsBase& GetStandardPaths();
#endif


#endif
// ADUNANZA END
};

// ADUNANZA BEGIN
// Per wxWidgets 2.9.x e Snow Leopard
//
// #ifndef __WXMSW__  COMMENTATA PER ADUNANZA
// ADUNANZA END
	void OnSignalChildHandler(int signal, siginfo_t *siginfo, void *ucontext);
	pid_t AmuleWaitPid(pid_t pid, int *status, int options, wxString *msg);
#endif // __WXMSW__


class CamuleDaemonApp : public CamuleApp
{
private:
// ADUNANZA BEGIN
// Per wxWidgets 2.9.x e Snow Leopard

#ifdef AMULED28

// ADUNANZA END

	bool m_Exit;
	CAmuledGSocketFuncTable *m_table;
// ADUNANZA BEGIN
// Per wxWidgets 2.9.x e Snow Leopard

#if 0 
#ifndef __WXMSW__
	struct sigaction m_oldSignalChildAction;
	struct sigaction m_newSignalChildAction;
#endif // __WXMSW__
#endif // if 0

#endif // AMULED28
// ADUNANZA END

	bool OnInit();
	int OnRun();
	int OnExit();

	virtual int InitGui(bool geometry_enable, wxString &geometry_string);

// ADUNANZA BEGIN
// Per wxWidgets 2.9.x e Snow Leopard
#ifndef __WXMSW__
	struct sigaction m_oldSignalChildAction;
	struct sigaction m_newSignalChildAction;
public:
	wxAppTraits *CreateTraits();
#endif // __WXMSW__
// ADUNANZA END


public:

// ADUNANZA BEGIN
// Per wxWidgets 2.9.x e Snow Leopard

#ifdef AMULED28

// ADUNANZA END
	CamuleDaemonApp();
	
	void ExitMainLoop() { m_Exit = true; }
// ADUNANZA BEGIN
// Per wxWidgets 2.9.x e Snow Leopard

#endif

#ifdef AMULED_DUMMY
	void ExitMainLoop() {}
#endif

// ADUNANZA END
	
	bool CopyTextToClipboard(wxString strText);
	
	virtual void ShowAlert(wxString msg, wxString title, int flags);
	
	void OnLoggingEvent(CLoggingEvent& evt);
	
	DECLARE_EVENT_TABLE()
// ADUNANZA BEGIN
// Per wxWidgets 2.9.x e Snow Leopard
#if 0	
	wxAppTraits *CreateTraits();
#endif
// ADUNANZA END
};

DECLARE_APP(CamuleDaemonApp)
#ifdef AMULE_CPP
	CamuleDaemonApp *theApp;
#else
	extern CamuleDaemonApp *theApp;
#endif

#endif /* ! AMULE_DAEMON */

#endif // AMULE_H
// File_checked_for_headers
