#include "../common/types.h"
#include "../common/linked_list.h"
#include "../common/timer.h"
#include "../common/database.h"
#include "mob.h"
#include "npc.h"
#include "client.h"

class GuildWars;
class GuildObjects;
class GuildNPCs;
class GuildLocation;
class GuildLocationList;

#define GWDEBUG

class GuildWars
{
public:
	void	UpdateGuildWarsPoints(int32 charid,sint32 points);
	void	DeathPointUpdate(int32 attackerid,int32 defenderid);

	bool	PurchaseNPC(Client* clientloc,int32 npcid);
	sint32	GetCurrentGuildFaction(Mob* mobone,Mob* mobtwo);

	sint32	CalculateFactionDecrease(Mob* killed,Mob* killedby);
	sint32	CalculateFactionIncrease(Mob* killed,Mob* killedby);

	GuildWars(void);
	~GuildWars(void);

	void Process();
	void Construct();
	void Deconstruct();
	void Update();

	char*		GetRandomName();

	int32		GetCurrentZone() { return current_zone; }
	int32		GetCurrentUsers() { return current_users; }
	int32		GetMaxUsers() { return max_users; }
	int8		GetCitiesCount() { return cities; }
	int8		GetTownsCount() { return towns; }
	int8		GetCampsCount() { return camps; }
	int8		GetMinimumLevel() { return minlevel; }
	int8		GetPVPAbility() { return pvpability; }
	int8		GetZoneStatus() { return status; }

	void		SetZoneStatus(int8 _status) { status = _status; }
	void		SetCurrentZone(int32 _current_zone) { current_zone = _current_zone; }
	void		SetMaxUsers(int32 _max_users) { max_users = _max_users; }
	void		SetCurrentUsers(int32 _current_users) { current_users = _current_users; }
	void		SetCitiesCount(int8 _cities) { cities = _cities; }
	void		SetTownsCount(int8 _towns) { towns = _towns; }
	void		SetCampsCount(int8 _camps) { camps = _camps; }
	void		SetMinimumLevel(int8 _minlevel) { minlevel = _minlevel; }
	void		SetPVPAbility(int8 _pvpability) { pvpability = _pvpability; }
protected:
	int32		current_zone; //current zone id
	int32		current_users; //current users in the zone
	int32		max_users; //max users ever to be in the zone
	int8		cities; //Cities in the zone
	int8		towns; //Towns in the zone
	int8		camps; //Camps in the zone
	int8		minlevel; //Minimum Level a client must be before max_users will start increasing
	int8		status; //0=Down,1=Up
	int8		pvpability; //0=No Restriction, 1=No Attacking Ability, 2=No GuildWars Combat

	friend class GuildLocationList;
};

class GuildObjects
{

};

class GuildNPCs
{
public:
	GuildNPCs(NPC* npc);
	bool	IsAlive() { return alive; }
	void	SetDead() { alive = false; }
	NPC*	ToNPC() { return npcpointer; }
	int32	NPCSpawnID() { return spawn_id; }
	void	UpdateReferences(NPC* npc);
	float	GetStartX() { return start_x; }
	float	GetStartY() { return start_y; }
	float	GetStartZ() { return start_z; }
	int32	GetKilledByLastGuildID() { return killedlastbyguildid; }
	void	KilledByGuildID(int32 guild_id) { killedlastbyguildid = guild_id; }
private:
	bool	alive;
	NPC*	npcpointer;
	int32	spawn_id;
	int32	killedlastbyguildid;
	float	start_x;
	float	start_y;
	float	start_z;
};

class GuildLocation
{
public:
	GuildLocation(int32 locid, float xcoord, float ycoord, float zcoord,int32 zone,int8 type,int32 guild);
	~GuildLocation();

	void	AddNPC(NPC* npc);
	bool	GuardsStillStanding();
	int32	GetLocationID() { return location_id; }
	void	SetGuildOwner(int32 newguildid) { guildid = newguildid; }
	int32	GetGuildOwner() { return guildid; }
	int32	GetZoneID() { return zoneid; }
	int8	GetLocationType() { return locationtype; }

	bool	Process();
	bool	TakeOverProcess();
	void	TakeOverLocation(int32 guildid);
	void	ResetNPCs();
	void	ResetObjects();

	void	SetProfit(int32 set) { profit = set; }
	int32	GetProfit() { return profit; } // Profit earned from owning location in copper

	int8	GuardsSpotsRemaining();

	GuildNPCs*	FindGuildNPCBySpawnID(int32 spawn_id);

	bool	PermittableGuardDistance(Client* clientloc);

	bool	TakeOverInProcess() { return takeoverprocess; }

	float	GetX() { return x; }
	float	GetY() { return y; }
	float	GetZ() { return z; }
private:
	Timer*	takeover_delay; // This timer is for the 30 minute delay of taking over a city
	Timer*	takeover_check;	// This timer is to slow down the number of checks, maybe once per minute
	Timer*	profit_timer; // This timer controls profit earned
	int32	location_id;
	float	x;
	float	y;
	float	z;
	int32	zoneid;
	int8	locationtype;
	int32	guildid;
	int32	profit;	//Profit in copper
	bool	continueprocess;
	bool	takeoverprocess;
	LinkedList<GuildNPCs*> guildnpcs;
	LinkedList<GuildObjects*> guildobjects;
};

class GuildLocationList
{
public:
	GuildLocationList(void);
	~GuildLocationList(void);

	float	GetMeleeAttackBonus(int32 guildid);
	float	GetCasterAttackBonus(int32 guildid);

	bool	RemoveLocation(int32 locid);
	void	AddLocation(GuildLocation* gl);
	void	ClearLocations();
	void	ProcessLocations();

	int32	GetGuildProfit(int32 guildid);

	float	GetDistance(float x1,float y1, float z1, float x2, float y2, float z2);

	GuildLocation*	FindClosestLocationByClient(Client* client);
	GuildLocation*	FindLocationByID(int32 locid);
private:
	LinkedList<GuildLocation*> list;
};

#define MAXMEMBERS				20
#define NOGUILDCAPLEVEL			21
#define SETLEVEL				50
#define GAINLEVEL				51
//Experience Rules
#define EXPLOSSLVLDIFF			20
#define EXPHNOCHGLVLDIFF		10
#define EXPLNOCHGLVLDIFF		-25
//Level Restriction Rules (no <= or >= all < or > functions unless using opposite of proper use, then sign + equal to)
#define NORESTRICTIONS			21	// Less Than: No rules, freely do whatever
#define MIDLEVELRESTRICT		20	// Greater Than: if person is not in a guild, cannot buff others in guilds and guilds cannot buff this person (TBD: Lvl 20-30, Slower experience than people in guilds?)
#define MIDHIGHLEVELRESTRICT	29	// Greater Than: cannot level past 30 without guild, cannot buff others in guilds and guilds cannot buff this person.
#define HIGHLEVELRESTRICT		39	// Greater Than: guild is required to level, if no guild, guilds can PvP the target, player cannot be buffed by members in guilds and cannot buff members in guilds.
//Guildwars Faction System
#define GW_ALLY					2000
#define GW_WARMLY				1600
#define GW_KINDLY				1200
#define GW_AMIABLY				800
#define GW_INDIFFERENTLY		400
#define GW_APPREHENSIVE			-1
#define GW_DUBIOUS				-400
#define GW_THREATNINGLY			-800
#define GW_SCOWL				-2000
#define GW_DEFAULTFACTION		-799
#define GW_FACTIONNOTEXIST		-2001
//Guildwars location flags
#define CITY					0
#define CAMP					1
#define GUILDHOUSE				2
#define	TOWER					3
//Guildwars Radius Restrictions
#define NPCTONPCRADIUS			50
#define	OUTTERCITYRADIUS		1200 // Probably will be no restriction at all, thats why its such a large number
#define OUTTERCAMPRADIUS		300
#define	OUTTERGUILDHOUSERADIUS	150
#define OUTTERTOWERRADIUS		100
#define	INNERCITYRADIUS			0
#define	INNERCAMPRADIUS			10
#define	INNERGUILDHOUSERADIUS	10 // Force players to spawn NPCs outside the guild house, because it is locked, dont' want NPCs protected because they are hiding and casting inside a house.
#define	INNERTOWERRADIUS		0
//Guildwars hard coded npc limits
#define MAXCITYNPCS				35
#define	MAXCAMPNPCS				20
#define	MAXGUILDHOUSENPCS		5
#define	MAXTOWERNPCS			3
//Guildwars profit increments (every 30 minutes)
#define CITYPROFIT				300000
#define CAMPPROFIT				0
#define GUILDHOUSEPROFIT		0
#define TOWERPROFIT				0
//Guildwars melee percentage bonus (per location)
#define MELEECITYBONUS			.10
#define MELEECAMPBONUS			.07
#define MELEEGUILDHOUSEBONUS	.05
#define MELEETOWERBONUS			.025
//Guildwars caster percentage bonus (per location)
#define CASTERCITYBONUS			.09
#define CASTERCAMPBONUS			.06
#define CASTERGUILDHOUSEBONUS	.04
#define CASTERTOWERBONUS		.02