#pragma once
#include "olcPixelGameEngine.h"
#include "Animation.h"
#include "olcUTIL_Animate2D.h"
#include "Monster.h"
#include "olcPGEX_TransformedView.h"
#include "Player.h"
#include "olcUTIL_Camera2D.h"
#include "Bullet.h"
#include "Effect.h"
#include "Map.h"
#include "TMXParser.h"

struct TilesheetData{
	TilesetData&tileset;
	int firstgid;
};

class Crawler : public olc::PixelGameEngine
{
	friend class sig::Animation;
	Camera2D camera;
	Player player;
	Renderable GFX_Warrior_Sheet,GFX_Slime_Sheet,GFX_Circle,
		GFX_Effect_GroundSlam_Back,GFX_Effect_GroundSlam_Front,
		GFX_Heart,GFX_BLOCK_BUBBLE,GFX_Ranger_Sheet,GFX_Wizard_Sheet,
		GFX_Battlecry_Effect,GFX_Mana,GFX_SonicSlash,GFX_EnergyParticle,
		GFX_Splash_Effect,GFX_LightningBolt,GFX_LightningBoltParticle1,
		GFX_LightningBoltParticle2,GFX_LightningBoltParticle3,GFX_LightningBoltParticle4,
		GFX_ChainLightning,GFX_LightningSplash;
public:
	Renderable GFX_BulletCircle,GFX_BulletCircleOutline,GFX_EnergyBolt;
	Pathfinding pathfinder;
private:
	std::vector<Effect>foregroundEffects,backgroundEffects;
	std::map<MapName,Map>MAP_DATA;
	std::map<std::string,TilesetData>MAP_TILESETS;
	vf2d worldShake={};
	float worldShakeTime=0;
	float lastWorldShakeAdjust=0;
	vf2d worldShakeVel={};
	const float WORLD_SHAKE_ADJUST_MAX_TIME=0.4;
	MapName currentLevel=MapName::CAMPAIGN_1_1;
	std::vector<TileGroup>foregroundTileGroups;
	std::vector<TileGroup>upperForegroundTileGroups;
	int bridgeLayerIndex=-1;
	float bridgeFadeFactor=0.f;
public:
	Crawler();

public:
	geom2d::rect<int>NO_COLLISION={};
	vi2d WORLD_SIZE={120,8};
	TileTransformedView view;
	bool OnUserCreate() override;
	bool OnUserUpdate(float fElapsedTime) override;
	void InitializeLevel(std::string mapFile,MapName map);
	void LoadLevel(MapName map);
	void HandleUserInput(float fElapsedTime);
	void UpdateCamera(float fElapsedTime);
	void UpdateEffects(float fElapsedTime);
	void UpdateBullets(float fElapsedTime);
	void RenderWorld(float fElapsedTime);
	void RenderHud();
	void AddEffect(Effect foreground,Effect background);
	//If back is true, places the effect in the background
	void AddEffect(Effect foreground,bool back=false);
	void HurtEnemies(vf2d pos,float radius,int damage,bool upperLevel);
	vf2d GetWorldMousePos();
	bool LeftHeld();
	bool RightHeld();
	bool UpHeld();
	bool DownHeld();
	bool LeftReleased();
	bool RightReleased();
	bool UpReleased();
	bool DownReleased();
	Player&GetPlayer();
	void SetupWorldShake(float duration);
	vi2d GetWorldSize();
	//tileID is the tile number from the tilesets.
	bool IsForegroundTile(TilesheetData sheet,int tileID);
	//tileID is the tile number from the tilesets.
	bool IsUpperForegroundTile(TilesheetData sheet,int tileID);
	//tileID is the tile number from the tilesets.
	TilesheetData GetTileSheet(MapName map,int tileID);
	//Gets the rectangle of the tile collision at this tile. If upperLevel is set to true, the collision tile must be in a Bridge class layer for the tile to hit. Also, zones containing LowerBridgeCollision will apply when upperLevel is set to false.
	geom2d::rect<int>GetTileCollision(MapName map,vf2d pos,bool upperLevel=false);
	//Checks if the point resides inside of a collision tile.
	bool HasTileCollision(MapName map,vf2d pos,bool upperLevel=false);
	MapName GetCurrentLevel();
	bool IsBridgeLayer(LayerTag&layer);
	std::map<std::string,std::vector<geom2d::rect<int>>>&GetZoneData(MapName map);
	void PopulateRenderLists(std::vector<Monster*>&monstersBeforeLower,std::vector<Monster*>&monstersBeforeUpper,std::vector<Monster*>&monstersAfterLower,std::vector<Monster*>&monstersAfterUpper,std::vector<Bullet*>&bulletsLower,std::vector<Bullet*>&bulletsUpper,std::vector<Effect*>&backgroundEffectsLower,std::vector<Effect*>&backgroundEffectsUpper,std::vector<Effect*>&foregroundEffectsLower,std::vector<Effect*>&foregroundEffectsUpper);
};