#ifndef _logic_h
#define _logic_h

enum logicstates
{
	NOTHING_HAPPENING = 0,
	AI_TURN,
	IN_BATTLE,
	UNIT_SELECTED,
	UNIT_MOVING,
	UNIT_MOVING_AND_ATTACKING,
	SAVING_GAME,
	IN_GENERAL_MENU,
	IN_UNIT_BUILD_MENU,
	MECHANIC_CAPPING, // MECHANIC_CAPPING is a mechanic capturing an enemy UNIT, not a building
	UNIT_UNLOADING,
	UNIT_TELEPORTING,
	TELEPORT_ANIMATION,
	SCROLLING,
	ONE_TEAM_LEFT,
	BACK_TO_MAIN_MENU,
	WINNER,
	FADE_EXIT,
	TIME_UP_INDICATOR,
	EXPLODING,
	PLAYER_DEFEATED,
	IN_OPTIONS_MENU,
	NET_WAITING_FOR_RESPONSE, // NET_WAITING_FOR_RESPONSE is only for the client (when they have asked the server to move a unit or something)
	START_TURN_SYNC,
	IN_HELP_SCREEN
};


typedef struct _unitexplosion
{
	int tx;
	int ty;
	float frame;
	int exists;
	bool notaunit_oilderrick;  //ugly hack to reuse explosion code to let people know when an oil derrick has been used up
} _unitexplosion;

extern vector<_unitexplosion> boom;
extern list<_particle> p_effects;

bool rotate_units(_unit *a, _unit *d, int rotationspeed);
bool battle_attack(_unit *a, _unit *d);

void draw_tiles(int scrollx, int scrolly, int editing, int x1, int y1, int w, int h, int keep_units);
void draw_tiles(int scrollx, int scrolly, int editing, int keep_units);
void avoid_map_gaps();

int do_battle(_unit *a, _unit *d);
int do_ai(int plyr);
int do_ai(int plyr, bool reset_everything);
int any_unit_here(int tx, int ty);
int do_gameoptions(bool ingame);
float total_damage(_unit *a, _unit *d);


string unit_name(int type);
int unit_type(string name);

extern vector<int> movelist;

class gamestate
{
public:
	bool game_just_started;
	bool loaded_from_file;
	
	
	bool new_turn;
	bool typingchat;
	bool netclient_multiple_actions;  //special case - if we need to know that the network client is doing two things at once (eg, move + attack)
	unsigned int netclient_response_wait_time;
	
	enum logicstates state;
	
	_unit *attacker, *defender;
	
	_loc build_menu_factory_tile;
	int build_menu_factory_type;
	
	_loc old_mouse_location;
	
	int unload_slot;  //the slot being unloaded (used when selecting where to unload)
	
	int windelay;  //delay between victory and the "victory!" animation
	
	// this group shouldn't be changed in reset()
	int pturn;
	int loaded_time;
	int time;
	int theplayer;
	int techlevel;
	int cashturns;
	_unit *unitselected;
	
	
	static gamestate *getinstance()
	{
		static gamestate state;
		return &state;
	}
	
	void next_turn();
	void reset();
	
	
protected:
	gamestate() :
		game_just_started (true),
		loaded_from_file (false),
		new_turn (true),
		typingchat (false),
		netclient_multiple_actions (false),
		netclient_response_wait_time (0),
		state (NOTHING_HAPPENING),
		attacker (0),
		defender (0),
		build_menu_factory_tile (_loc()),
		build_menu_factory_type (-1),
		old_mouse_location (_loc()),
		unload_slot (-1),
		windelay (0),
		pturn (0),
		loaded_time (-1),
		time (0),
		theplayer (0),
		techlevel (-1),
		cashturns (0),
		unitselected (0)
	{
		reset();
	}
	
	gamestate(const gamestate&);
	gamestate& operator= (const gamestate&);
};

void defeated_player_check();
void check_minimap(int &m);
void set_moves(int plyr, int unitnum, int tx, int ty);
void clear_moveselect();
void draw_path(_unit *u);
void draw_unitstats(_unit *u, int x, int y);
void transform_buildings(int plyr, int plyr2);
void repair_units(int plyr);
void scroll_to_hq(int plyr);
void play_moving_sound(int utype);
void init_explode(int x, int y);
void init_deadoilderrick(int tx, int ty);
void do_power();
void capture_building(_unit* u);
void merge_units(_unit *merger, int tx, int ty);
void check_scrolling();
void check_scrolling(int forcex, int forcey);
void debug_savegame();
void destroy_player_units(int theplayer);
void time_up();
void logic_netchat(string message = "");
void move_unit(_unit *u);
void update_cities();
void update_burning();
void do_firedamage(_unit *u, int damage);
void broadcast_unithealth(_unit *u);
void get_unithealth(DyBytes *data);
void broadcast_tiledata();
void get_tiledata(DyBytes *data);
void draw_net_icon(int x, int y);
void draw_wait_icon(int x, int y);
void mechanic_capture(_unit *capper, int captx, int capty);
void start_teleport_animation(_unit *u, int tx, int ty);
void teleport_animation(_unit *initunit, int tx, int ty);
void client_netbattle();
void draw_shieldrange(_unit *u);
void do_surrender(int from, int to);
void get_good_textpos(_tile *t, const string &str, int *px, int *py);
bool convert_theplayers_units(int from, int to);
bool one_team_left();
bool player_defeated(int plyr);
bool move_overlap(_unit *u);
bool can_merge(_unit *a, _unit *b);
bool type_can_attack(_unit *a, _unit *d);
bool unit_unloadable_here(int ox, int oy, int tx, int ty, int type);
bool check_explodes();
bool sync_burning();
bool help_screen();
int do_explodes();
int scroll_to_location(int x, int y);
int attackable_unit_here(_unit *attacker, int tx, int ty);
int attackable_unit_here(_unit *attacker, int tx, int ty, bool ignore_teams);
int unit_here_thorough(int plyr, int tx, int ty, int ignore);
int moves_needed(int mtype, int tx, int ty, int plyr);
int get_ltype(int tx, int ty);
int do_moveselect(int plyr, int u, int tx, int ty);
int list_distance(_unit *u);
int do_unitmenu(int menutype, int tx, int ty, int pturn);
int money_producing_buildings_owned(int plyr);
int rounded_health(float h);
int unit_exists(int plyr);
int do_savemenu();
int secure_base(int plyr);
int reconnect();
string do_generalmenu();
string do_actionmenu(_unit *u);
_loc movelist_result(_unit *u);
_loc nearest_tile_to(_loc target);

void init_logic();
void battle();
void windelay();
void ai();
void netplayer();
void nothing_happening();
void unit_moving();
void unit_moving_and_attacking();
void unit_selected();
void mechanic_capping();
void unit_unloading();
void unit_teleporting();
void build_menu();
void general_menu();

void show_movable_tiles(_unit *u, float alpha);
void draw_attackables(vector<_loc> locations);
void show_unload_locations(vector<_loc> locations);
vector<_loc> find_attackables(_unit *u);
vector<_loc> find_unload_locations(_unit *u, int type);

void do_sidebar(int p, _unit *u, bool drawonly = false, bool reset = false);

#endif
