#pragma once

#include <vector>

#include "../Assets/Constants.h"
#include "../Instantiation.h"
#include "Item.h"
#include "Human.h"
#include "Townsfolk.h"
#include "Artisan.h"
#include "Soldier.h"
#include <iosfwd>
#include "Mover.h"

namespace mechanics {
	class PlayerGame {
		friend void ::createMap(assets::Map &map);
	public:
		static PlayerGame &newGame() {
			if(sCurrent) {
				delete sCurrent;
			}

			sCurrent = new PlayerGame();

			return *sCurrent;
		}

		static PlayerGame &current() {
			return *sCurrent;
		}

		static bool isInGame() {
			return sCurrent!=NULL;
		}

		// citizens
		void increaseCitizenDeaths() {
			mCitizenDeaths++;
		}

		int getCitizenDeaths() const {
			return mCitizenDeaths;
		}

		int getCitizensAlive() const {
			//will we keep dead people?
			return mHumanList.size();
		}

		std::vector<Human*> &getHumanList() {
			return mHumanList;
		}

		std::vector<Townsfolk*> &getTownsfolkList() {
			return mTownsfolkList;
		}

		std::vector<Soldier*> &getSoldierList() {
			return mSoldierList;
		}

		std::vector<Artisan*> &getArtisanList() {
			return mArtisanList;
		}

		std::vector<MilitaryBuilding*> &getMilitaryBuildingList() {
			return mMilitaryBuildingList;
		}

		std::vector<TownBuilding*> &getTownBuildingList() {
			return mTownBuildingList;
		}

		std::vector<Building*> &getBuildingList() {
			return mBuildingList;
		}

		void addTownsfolk(Townsfolk &townsfolk);
		void addSoldier(Soldier &soldier);
		void addArtisan(Artisan &artisan);

		void destroyHuman(Human *ptr);
		void destroyTownsfolk(Townsfolk *ptr);
		void destroySoldier(Soldier *ptr);
		void destroyArtisan(Artisan *ptr);

		Townsfolk *spawnTownsfolk();
		gge::utils::Point findHumanSpawnPoint();

		void killTownsfolk(Townsfolk *ptr);
		void killSoldier(Soldier *ptr);
		void killArtisan(Artisan *ptr);

		// buildings
		void increaseBuildingConstructed() {
			mBuildingConstructed++;
		}

		int getBuildingConstructed() const {
			return mBuildingConstructed;
		}

		void increaseBuildingDestructed() {
			mBuildingDestructed++;
		}

		int getBuildingDestructed() const {
			return mBuildingDestructed;
		}

		float getBuildingDestructionRate() const {
			return (float)mBuildingDestructed / (float)mBuildingConstructed;
		}

		int getBuildingsAlive() const {
			return mBuildingConstructed - mBuildingDestructed;
		}

		void townCenterLoc(const gge::utils::Bounds &location) {
			mTownCenterLoc = location;
		}

		gge::utils::Bounds townCenterLoc() const {
			return mTownCenterLoc;
		}

		gge::utils::Bounds getTownBounds() const {
			return mTownBounds;
		}

		void setTownBounds(gge::utils::Bounds givenBounds) {
			mTownBounds = givenBounds;
		}

		void destroyBuilding(Building &tb);

		void addTownBuilding(TownBuilding &tb);
		void destroyTownBuilding(TownBuilding &tb);

		MilitaryBuilding *createMilitaryBuilding(const std::string &ID);
		void addMilitaryBuilding(MilitaryBuilding &mb);
		void destroyMilitaryBuilding(MilitaryBuilding &mb);

		gge::utils::Point findTownBuildingSpawnPoint(gge::utils::Size size);
		TownBuilding *spawnTownBuilding();

		// dens
		void addDen(Den &den);
		void destroyDen(Den &den);

		std::vector<Den*> &getDenList() {
			return mDenList;
		}

		// wildlings
		void addWildling(Wildling &wildling);
		void destroyWildling(Wildling &wildling);

		// taxes and golds
		float taxRate() const {
			return mTaxRate;
		}

		void taxRate(float value) {
			mTaxRate = value;
		}

		int gold() const {
			return mGold;
		}

		int income() const;

		int goldReal() const {
			return mGold + mGoldDec;
		}

		void CheckTaxes();

		bool IncreaseGold(int amount) {
			mGoldDec += amount;

			return true;
		}

		bool ConsumeGold(int amount) {
			if(goldReal() < amount) {
				return false;
			}

			mGoldDec -= amount;
			return true;
		}

		// happiness
		float getCurrentHappiness() const {
			return mCurrentHappiness;
		}

		void addHappiness(float amount) {
			mCurrentHappiness+=amount;
		}

		float getTaxHappiness() const {
			//!constant: can be used to limit # of citizens
			return assets::constants::happiness::populationLim - (taxRate() * assets::constants::happiness::taxRateMultiplier);
		}

		// crafting
		bool SearchBuilding(std::string buildingId);
		bool CheckCraft(std::string itemId, bool log=true);

		void addItem(Item &item);
		void destroyItem(Item &item);
		StorageBuilding *takeItem(Item &item);

		std::vector<Item*> &getCraftedItemList() {
			return mCraftedItemList;
		}

		// misc
		void UpdatePlayerGame();

		void SpawnCheck();

		void resetTime() {
			mPrevTime=gge::Main.CurrentTime;
		}

		int populationLimit() const { return mPopulationLimit; }

		// game log
		std::vector<std::string> &getGameLog() {
			return mGameLog;
		}

		void AddToGameLog(std::stringstream &stream) {
			AddToGameLog(stream.str());
		}

		void AddToGameLog(const std::string line) {
			//! constant - gamelog size
			while(mGameLog.size() > 10) {
				mGameLog.erase(mGameLog.begin());
			}

			mGameLog.push_back(line);
		}

		int soldierHousing() const {
			return mSoldierHousing;
		}

		int getUnitCount() const {
			return mSoldierList.size() + mArtisanList.size();
		}

		void pause() {
			mIsPaused=true;
		}

		void resume() {
			mIsPaused=false;
			mPrevTime=gge::Main.CurrentTime;
		}

		void endGame() {
			delete sCurrent;
			sCurrent=NULL;
		}

		~PlayerGame() {
			gge::Main.BeforeRenderEvent.Unregister(this, &PlayerGame::UpdatePlayerGame);
		}

		float gameSpeed() const { return mGameSpeed; }
		void gameSpeed(float value) { mGameSpeed=value; }

	protected:
		static PlayerGame *sCurrent;

		gge::utils::Bounds mTownCenterLoc;

		int mCitizenDeaths;
		int mBuildingConstructed;
		int mBuildingDestructed;
		float mTaxRate;
		float mCurrentHappiness;

		int mCurrentTownsfolkCapacity;
		int mSoldierHousing;

		unsigned int mLastTownsfolkSpawn;
		unsigned int mLastTownBuildingSpawn;
		unsigned int mLastGoldConsume;

		unsigned int mPrevTime;

		float mGameSpeed;
		int mPopulationLimit;

		int mGold;
		int mGoldDec;

		bool mIsPaused;

		std::vector<std::string> mGameLog;

		std::vector<Human*> mHumanList;
		std::vector<Townsfolk*> mTownsfolkList;
		std::vector<Soldier*> mSoldierList;
		std::vector<Artisan*> mArtisanList;
		std::vector<TownBuilding*> mTownBuildingList;
		std::vector<MilitaryBuilding*> mMilitaryBuildingList;
		std::vector<Building*> mBuildingList;
		std::vector<Den*> mDenList;
		std::vector<Wildling*> mWildlingList;
		std::vector<Item*> mCraftedItemList;

		std::vector<Mover*> mMoverList;


		gge::utils::Bounds mTownBounds;

		PlayerGame() : mTaxRate(20), mCurrentHappiness(60), mCitizenDeaths(0),
			mGold(0), mGoldDec(0), mCurrentTownsfolkCapacity(0), mGameSpeed(1),
			mTownBounds(-1,-1,-1,-1), mSoldierHousing(0), mIsPaused(false)
		{
			mPrevTime=gge::Main.CurrentTime;
			mLastTownsfolkSpawn = gge::Main.CurrentTime;
			mLastTownBuildingSpawn = gge::Main.CurrentTime;
			mLastGoldConsume = gge::Main.CurrentTime;
			currentGameTime=0;
			gge::Main.BeforeRenderEvent.Register(this, &PlayerGame::UpdatePlayerGame);
		}
	};
}