// ------------------------------------------------
// File : servmgr.h
// Date: 4-apr-2002
// Author: giles
// Desc: 
//
// (c) 2002 peercast.org
// ------------------------------------------------
// 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.
// ------------------------------------------------

#ifndef _SERVMGR_H
#define _SERVMGR_H

#include "servent.h"
// ----------------------------------
class ServHost
{
public:
	enum TYPE
	{
		T_NONE,
		T_STREAM,
		T_CHANNEL,
		T_SERVENT,
	};

	ServHost() {init();}
	void init()
	{
		host.init();
		time = 0;
		type = T_NONE;
	}
	void init(Host &h, TYPE tp, unsigned int tim,GnuID id)
	{
		netid = id;
		host = h;
		type = tp;
		if (tim)
			time = tim;
		else
			time = sys->getTime();
	}

	static const char *getTypeStr(TYPE);
	static TYPE getTypeFromStr(const char *);

	GnuID net;
	TYPE type;
	Host host;
	GnuID netid;
	unsigned int time;
};
// ----------------------------------
class ServFilter 
{
public:
	enum 
	{
		F_PRIVATE  = 0x01,
		F_BAN	   = 0x02,
		F_NETWORK  = 0x04,
		F_DIRECT   = 0x08
	};

	ServFilter() {init();}
	void	init()
	{
		flags = 0;
		host.init();
	}

	Host host;
	unsigned int flags;
};

// ----------------------------------
// ServMgr keeps track of Servents
class ServMgr
{



public:

	enum NOTIFY_TYPE
	{
		NT_UPGRADE			= 0x0001,
		NT_PEERCAST			= 0x0002,
		NT_BROADCASTERS		= 0x0004,
		NT_TRACKINFO		= 0x0008
	};

	enum FW_STATE
	{
		FW_OFF,
		FW_ON,
		FW_UNKNOWN
	};
	enum {

		MAX_BITRATE		= 128,		// max. Kbits/s output

		MAX_HOSTCACHE = 100,		// max. amount of hosts in cache
		MIN_HOSTS	= 3,			// min. amount of hosts that should be kept in cache

		MAX_SERVENTS = 32,			// max. number of available servents
		MAX_OUTGOING = 3,			// max. number of outgoing servents to use
		MAX_INCOMING = 6,			// max. number of incoming servents to use
		MAX_TRYOUT   = 10,			// max. number of outgoing servents to try connect
		MIN_CONNECTED = 3,			// min. amount of connected hosts that should be kept

		MAX_FILTERS = 50,

		MAX_VERSIONS = 16,

		MAX_PREVIEWTIME	= 300,		// max. seconds preview per channel available (direct connections)
		MAX_PREVIEWWAIT = 300,		// max. seconds wait between previews 

	};

	enum AUTH_TYPE
	{
		AUTH_COOKIE,
		AUTH_HTTPBASIC
	};

	

	ServMgr();

	bool	start();

	Servent	*findServent(unsigned int,unsigned short,GnuID &);
	Servent	*findServent(Servent::TYPE);
	Servent	*findServent(Servent::TYPE,Host &,GnuID &);
	Servent *findOldestServent(Servent::TYPE);

	Servent	*allocServent();
	unsigned int		numUsed(int);
	unsigned int		numConnected(int);
	unsigned int		totalConnected()
	{
		return numConnected(Servent::T_OUTGOING) + numConnected(Servent::T_INCOMING);
	}
	unsigned int		numStreams(bool);
	unsigned int		numOutgoing();
	bool	isFiltered(int,Host &h);
	bool	addOutgoing(Host,GnuID &,bool);


	static	THREAD_PROC		serverProc(ThreadInfo *);
	static	THREAD_PROC		clientProc(ThreadInfo *);
	static	THREAD_PROC		idleProc(ThreadInfo *);

	int		broadcast(GnuPacket &,Servent * = NULL);
	int		route(GnuPacket &, GnuID &, Servent * = NULL);

	XML::Node *createServentXML();

	void		procConnectArgs(char *,GnuID &);

	// host cache
	void			addHost(Host &,ServHost::TYPE,unsigned int, GnuID &);
	int				getNewestServents(Host *,int, Host &);
	ServHost		getOutgoingServent(GnuID &);
	void			deadHost(Host &,ServHost::TYPE);
	unsigned int	numHosts(ServHost::TYPE);
	void			clearHostCache(ServHost::TYPE);
	bool			seenHost(Host &,ServHost::TYPE,unsigned int);

	void	setFirewall(FW_STATE);
	FW_STATE	getFirewall() {return firewalled;}
	void	saveSettings(const char *);
	void	loadSettings(const char *);
	void	setPassiveSearch(unsigned int);
	int		findChannel(ChanInfo &);
	void	setFilterDefaults();

	void	addVersion(unsigned int);

	unsigned int getUptime()
	{
		return sys->getTime()-startTime;
	}

	bool	seenPacket(GnuPacket &);

	bool	isReplyID(GnuID &id)
	{
		return replyIDs.contains(id);
	}
	void	addReplyID(GnuID &id)
	{
		replyIDs.addGnuID(id);
	}

	bool	needHosts()
	{
		return numHosts(ServHost::T_SERVENT) < maxTryout;
	}
	bool	needConnections() 
	{
		return totalConnected() < minConnected;
	}
	bool	tryFull() 
	{
		return maxTryout ? numUsed(Servent::T_OUTGOING) > maxTryout: false;
	}

	bool	inUsedFull() 
	{
		return maxIncoming ? numUsed(Servent::T_INCOMING) >= maxIncoming : false;
	}
	bool	inOver() 
	{
		return maxIncoming ? numConnected(Servent::T_INCOMING) > maxIncoming : false;
	}
	bool	inFull() 
	{
		return maxIncoming ? numConnected(Servent::T_INCOMING) >= maxIncoming : false;
	}
	bool	outUsedFull() 
	{
		return maxOutgoing ? numUsed(Servent::T_OUTGOING) >= maxOutgoing: false;
	}
	bool	outOver() 
	{
		return maxOutgoing ? numConnected(Servent::T_OUTGOING) > maxOutgoing : false;
	}
	bool	outFull() 
	{
		return maxOutgoing ? numConnected(Servent::T_OUTGOING) >= maxOutgoing : false;
	}

	bool	streamFull() 
	{
		return maxStreams ?  numStreams(false) >= maxStreams : false;
	}

	bool	bitrateFull(unsigned int br) 
	{
		return maxBitrate ? (BYTES_TO_KBPS(totalOutput(false))+br) > maxBitrate  : false;
	}

	unsigned int		totalOutput(bool);


	Servent servents[MAX_SERVENTS];
	WLock	lock;

	ServHost	hostCache[MAX_HOSTCACHE];

	char	password[64];

	bool	allowGnutella;
	unsigned int		maxBitrate,maxIncoming,maxOutgoing,maxStreams,maxTryout,minConnected;
	bool	isRoot;
	int		totalStreams;

	Host	serverHost;

	char	downloadURL[128];
	String	rootMsg;
	char	forceIP[64];
	char	connectHost[128];
	GnuID	networkID;
	unsigned int		firewallTimeout;
	int		showLog;
	int		shutdownTimer;
	bool	pauseLog;
	bool	forceNormal;
	bool	useFlowControl;

	bool	restartServer;
	bool	allowDirect;
	bool	autoConnect,autoServe,forceLookup;
	int		queryTTL;

	unsigned int		allowServer1,allowServer2;
	unsigned int		startTime;
	unsigned int		tryoutDelay;
	unsigned int		refreshHTML;
	unsigned int		relayBroadcast;
	unsigned int		serventBandwidth;
	unsigned int		maxPreviewTime;
	unsigned int		maxPreviewWait;

	unsigned int notifyMask;

	GnuIDList	replyIDs;
	GnuID		sessionID;

	ServFilter	filters[MAX_FILTERS];
	int	numFilters;

	CookieList	cookieList;
	AUTH_TYPE	authType;

	unsigned int	clientVersions[MAX_VERSIONS],clientCounts[MAX_VERSIONS];
	int	numVersions;


private:
	FW_STATE	firewalled;
};

// ----------------------------------
extern ServMgr *servMgr;


#endif
