roh/conf.old/area/
roh/config/code/python/
roh/config/game/area/
roh/config/game/signs/
roh/help/dmhelp/
roh/help/help/
roh/log/
roh/log/staff/
roh/monsters/ocean/
roh/objects/misc/
roh/objects/ocean/
roh/player/
roh/rooms/area/1/
roh/rooms/misc/
roh/rooms/ocean/
roh/src-2.47e/
/*
 * server.h
 *   Server class
 *   ____            _
 *  |  _ \ ___  __ _| |_ __ ___  ___
 *  | |_) / _ \/ _` | | '_ ` _ \/ __|
 *  |  _ <  __/ (_| | | | | | | \__ \
 *  |_| \_\___|\__,_|_|_| |_| |_|___/
 *
 * Permission to use, modify and distribute is granted via the
 *  Creative Commons - Attribution - Non Commercial - Share Alike 3.0 License
 *    http://creativecommons.org/licenses/by-nc-sa/3.0/
 *
 * 	Copyright (C) 2007-2012 Jason Mitchell, Randi Mitchell
 * 	   Contributions by Tim Callahan, Jonathan Hseu
 *  Based on Mordor (C) Brooke Paul, Brett J. Vickers, John P. Freeman
 *
 */

#ifndef SERVER_H_
#define SERVER_H_

#ifdef SQL_LOGGER

namespace odbc {
    class Connection;
}

#endif //SQL_LOGGER

// C Includes
#include "pythonHandler.h"
#include <netinet/in.h> // Needs: htons, htonl, INADDR_ANY, sockaddr_in

class Player;
class Group;
class PythonHandler;
class WebInterface;
class Socket;
class cmd;
class ReportedMsdpVariable;
class MsdpVariable;


//// Forward Declaration of PyObject
//struct _object;
//typedef _object PyObject;

enum childType {
	CHILD_START,

	CHILD_DNS_RESOLVER,
	CHILD_LISTER,
	CHILD_DEMOGRAPHICS,
	CHILD_SWAP_FIND,
	CHILD_SWAP_FINISH,
	CHILD_PRINT,

	CHILD_END
};
enum GoldLog {
    GOLD_IN,
    GOLD_OUT
};


#include "asynch.h"

#ifndef PYTHON_CODE_GEN
typedef std::map<bstring, MudObject*,idComp> IdMap;
#endif
typedef std::list<Monster*> MonsterList;
typedef std::list<Group*> GroupList;
typedef std::list<Socket*> SocketList;
typedef std::vector<Socket*> SocketVector;
typedef std::map<bstring, Player*> PlayerMap;
class Server
{

// **************
// Static Methods
public:
	static Server* getInstance();
	static void destroyInstance();

	~Server();
// Instance
private:
	static Server* myInstance;
protected:
	Server();


// *****************
// Public Structures
public:
	struct controlSock {
		int port;
		int control;
		controlSock(int port, int control) {
			this->port = port;
			this->control = control;
		}
	};
	struct childProcess {
		int pid;
		childType type;
		int fd; // Fd if any we should watch
		bstring extra;
		childProcess() {
			pid = 0;
			fd = -1;
			extra = "";
		}
		childProcess(int p, childType t, int f = -1, bstring e = "") {
			pid = p;
			type = t;
			fd = f;
			extra = e;
		}
	};
	struct dnsCache {
		bstring ip;
		bstring hostName;
		time_t time;
		dnsCache(bstring pIp, bstring pHostName, time_t pTime) {
			ip = pIp;
			hostName = pHostName;
			time = pTime;
		}
		bool operator==(const dnsCache& o) {
			return(ip == o.ip && hostName == o.hostName);
		}
	};

	// Temp public
public:
	PlayerMap players; // Map of all players
	SocketList sockets; // List of all connected sockets
	SocketVector* vSockets = 0;
	void handlePythonError();
	
// ******************
// Internal Variables
private:

	std::list<DelayedAction> delayedActionQueue;
	
	PythonHandler* pythonHandler;

	std::list<BaseRoom*> effectsIndex;

	fd_set inSet;
	fd_set outSet;
	fd_set excSet;

	bool running; // True while the game is up and bound to a port
	long pulse; // Current pulse

	bool rebooting;
	bool GDB;
	bool valgrind;

	// List of Ids
#ifndef PYTHON_CODE_GEN
	IdMap registeredIds;
#endif
	// List of groups
	GroupList groups;

	// Maximum Ids
	long maxPlayerId;
	long maxMonsterId;
	long maxObjectId;
	bool idDirty;

	std::list<childProcess> children; // List of child processes
	std::list<controlSock> controlSocks; // List of control fds
	std::list<dnsCache> cachedDns; // Cache of DNS lookups
	WebInterface* webInterface;

	// Game Updates
	MonsterList activeList; // The new active list

	long lastDnsPrune;
	long lastUserUpdate;
	long lastRoomPulseUpdate;
	long lastRandomUpdate;
	long lastActiveUpdate;

	int Deadchildren;


// ****************
// Internal Methods
private:
	// Python
	bool initPython();
	bool cleanUpPython();

	int getNumSockets(void); // Get number of sockets in the sockets list

	// Game & Socket methods
	int handleNewConnection(controlSock& control);
	int poll(void); // Poll all descriptors for input
	int checkNew(void); // Accept new connections
	int processInput(void); // Process input from users
	int processCommands(void); // Process commands from users
	int updatePlayerCombat(void); // Handle player auto attacks etc
	int processChildren(void);
	int processListOutput(childProcess &lister);

	// Child processes
	int reapChildren(void); // Clean up after any dead children

	// Reboot
	bool saveRebootFile(bool resetShips = false);

	// Updates
	void updateGame(void);
	void processMsdp(void);
	void pulseTicks(long t);
	void pulseCreatureEffects(long t);
	void pulseRoomEffects(long t);
	void updateUsers(long t);
	void updateRandom(long t);
	void updateActive(long t);

	// TODO: Get rid of this and switch all old "logic" creatures over to python scripts
	void updateAction(long t);

	// DNS
	void addCache(bstring ip, bstring hostName, time_t t = -1);
	void saveDnsCache();
	void loadDnsCache();
	void pruneDns();

	int installPrintfHandlers();
	void installSignalHandlers();

	void populateVSockets();

	// Delayed Actions
protected:
	void parseDelayedActions(long t);


#ifdef SQL_LOGGER

protected:
	odbc::Connection* conn;
	bool connActive;
    void cleanUpSql();
    bool initSql();
    bool logGoldSql(bstring& pName, bstring& pId, bstring& targetStr, bstring& source, bstring& room,
                    bstring& logType, unsigned long amt, bstring& direction);

public:
    bool getConnStatus();
    int getConnTimeout();
#endif // SQL_LOGGER


public:

    void clearAsEnemy(Player* player);
    bstring showActiveList();

	void logGold(GoldLog dir, Player* player, Money amt, MudObject* target, bstring logType);

    bool registerGroup(Group* toRegister);
    bool unRegisterGroup(Group* toUnRegister);
    bstring getGroupList();

	bool registerMudObject(MudObject* toRegister, bool reassignId = false);
	bool unRegisterMudObject(MudObject* toUnRegister);
	bstring getRegisteredList();
	Creature* lookupCrtId(const bstring& toLookup);
	Object* lookupObjId(const bstring& toLookup);
	Player* lookupPlyId(const bstring& toLookup);

	void loadIds();
	void saveIds();

	bstring getNextMonsterId();
	bstring getNextPlayerId();
	bstring getNextObjectId();

	long getMaxMonsterId();
	long getMaxPlayerId();
	long getMaxObjectId();

	bool removeDelayedActions(MudObject* target, bool interruptOnly=false);
	void addDelayedAction(void (*callback)(DelayedActionFn), MudObject* target, cmd* cmnd, DelayedActionType type, long howLong, bool canInterrupt=true);
	void addDelayedScript(void (*callback)(DelayedActionFn), MudObject* target, bstring script, long howLong, bool canInterrupt=true);
	bool hasAction(const MudObject* target, DelayedActionType type);
	bstring delayedActionStrings(const MudObject* target);

	void weather(WeatherString w);
	void updateWeather(long t);
// *******************************
// Public methods for server class
public:

	// Child processes
	void addChild(int pid, childType pType, int pFd = -1, bstring pExtra = "");

	// Python
	bool runPython(const bstring& pyScript, object& dictionary);
	bool runPython(const bstring& pyScript, bstring args = "", MudObject *actor = NULL, MudObject *target = NULL);
	bool runPythonWithReturn(const bstring& pyScript, bstring args = "", MudObject *actor = NULL, MudObject *target = NULL);
	bool runPython(const bstring& pyScript, bstring args, Socket *sock, Player *actor, MsdpVariable* msdpVar = NULL);

	// Setup
	bool init();	// Setup the server

	void setGDB();
	void setRebooting();
	void setValgrind();

	int run(void); // Run the server
	int addListenPort(int); // Add a new port to listen to

	// Status
	void sendCrash();

	bool isRebooting();
	bool isGDB();
	bool isValgrind();

	// Reboot
	bool startReboot(bool resetShips = false);
	int finishReboot(void); // Bring the mud back up from a reboot

	// DNS
	bstring getDnsCacheString();
	bool getDnsCache(bstring &ip, bstring &hostName);
	int startDnsLookup(Socket* sock, sockaddr_in pAddr); // Start dns lookup on a socket

	// Players
	bool addPlayer(Player* player);
	bool clearPlayer(Player* player);
	Player* findPlayer(bstring name);
	bool clearPlayer(bstring name);
	void saveAllPly();
	int getNumPlayers();

	// Sockets
	int deleteSocket(Socket* sock);
	void disconnectAll(void);
	int processOutput(void); // Send any buffered output

	// Web Interface
	bool initWebInterface();
	bool checkWebInterface();
	void recreateFifos();

	// Active list functions
	void addActive(Monster* monster);
	void delActive(Monster* monster);
	bool isActive(Monster* monster);

	// Child Processes
	void childDied();
	int getDeadChildren() const;
	int runList(Socket* sock, cmd* cmnd);
	bstring simpleChildRead(Server::childProcess &child);

	// Swap functions - use children
	bstring swapName();
	void finishSwap(Player* player, bool online, CatRef origin, CatRef target);
	bool swap(Swap s);
	void endSwap();
	void swapInfo(const Player* player);

	// Queries
	bool checkDuplicateName(Socket* sock, bool dis);
	bool checkDouble(Socket* sock);

	// Bans
	void checkBans();

	// Broadcasts
	bstring getTimeZone();

	// Effects
	void addEffectsIndex(BaseRoom* room);
	void removeEffectsIndex(BaseRoom* room);
	void removeEffectsOwner(const Creature* owner);
	void showEffectsIndex(const Player* player);

protected:
	int cleanUp(void); // Kick out any disconnectors and other general cleanup

};

#endif /*SERVER_H_*/