#pragma once
#include "../Assets/Buildings.h"
#include "Building.h"
#include "Item.h"

namespace mechanics
{
	class MilitaryBuilding: public Building
	{
	public:

		virtual float maximumHP() const {
			return provider().HP;
		}

		virtual float XPReward() const {
			return provider().HP/20+provider().size.Area()*2;
		}

		virtual float CalculateDamageReduction(Attacker *attacker, BaseWeapon *weapon, float damage) {
			return damage-provider().armor;
		}

		virtual void Killed(Attacker *attacker, BaseWeapon *weapon);

		std::string ID() const {
			return mProvider.ID;
		}

		virtual assets::MilitaryBuilding::Type type() {
			return mProvider.type;
		}

		const assets::MilitaryBuilding &provider() const {
			return mProvider;
		}

		virtual gge::utils::Size size() const {
			return provider().size;
		}

		virtual void locateTo(const gge::utils::Point &given_location)
		{
			Object::locateTo(given_location);	
			Object::setNonPassable(mProvider);

			for(auto it=mProvider.usablePoints.begin();it!=mProvider.usablePoints.end();++it)
				Map::current().getPointInfoMap()(*it+location).object=this;
		}

		virtual void setLocation(const gge::utils::Point &given_location)
		{
			for(auto it=mProvider.usablePoints.begin();it!=mProvider.usablePoints.end();++it)
				Map::current().getPointInfoMap()(*it+location).object=NULL;

			Object::setPassable(mProvider);
			Object::locateTo(given_location);
			Object::setNonPassable(mProvider);

			for(auto it=mProvider.usablePoints.begin();it!=mProvider.usablePoints.end();++it)
				Map::current().getPointInfoMap()(*it+location).object=this;
		}

		virtual void removeFromMap() {
			for(auto it=mProvider.usablePoints.begin();it!=mProvider.usablePoints.end();++it)
				Map::current().getPointInfoMap()(*it+location).object=NULL;

			Object::removeFromMap();
			Object::setPassable(mProvider);
		}


	protected:

		MilitaryBuilding(const assets::MilitaryBuilding &given_provider, Animator &given_animator) : mProvider(given_provider),
			Building(given_animator, OwnerType::player)
		{
			given_animator.setAnimation(North, "Stand");
			mHP=provider().HP;
		}


		const assets::MilitaryBuilding &mProvider;
	};

	class StorageBuilding : public MilitaryBuilding {
	public:
		StorageBuilding(const assets::MilitaryBuilding &provider, Animator &animator) : MilitaryBuilding(provider, animator) 
		{
			mCapacity= provider.capacity;
			mStored  = 0;
		}

		bool isAvailable() {
			return capacity()>stored();
		}

		int capacity() const {
			return mCapacity;
		}

		assets::Item::Type storageType() const {
			return mProvider.storageType;
		}

		int stored() const {
			return mStored;
		}

		bool takeOut(Item *item) {
			for(auto it=mContents.First();it.IsValid();it.Next()) {
				if(it.CurrentPtr()==item) {
					it.Remove();
					mStored--;
					if(stored()==0) {
						animator.setAnimation(North, "Empty");
					}
					return true;
				}
			}
			return false;
		}

		bool store(Item *item) {
			if(mStored>=mCapacity) return false;
			//if(item->type!=type()) return false;

			mContents.Add(item);
			mStored++;

			animator.setAnimation(North, "Full");

			return true;
		}

		gge::utils::Collection<Item>::Iterator First() {
			return mContents.First();
		}


	protected:
		int mStored, mCapacity;

		gge::utils::Collection<Item> mContents;
	};


	class HousingBuilding : public MilitaryBuilding {
	public:
		HousingBuilding(const assets::MilitaryBuilding &provider, Animator &animator) : MilitaryBuilding(provider, animator) 
		{
			mCapacity= provider.capacity;
			//mStored  = 0;
		}

		int capacity() const {
			return mCapacity;
		}

		//int stored() const {
		//	return mStored;
		//}

		//bool allocate() {
		//	if(mStored>=mCapacity) return false;

		//	mStored++;
		//	return true;
		//}

		//bool release() {
		//	if(mStored<=0) return false;

		//	mStored--;
		//	return true;
		//}


	protected:
		int /*mStored, */mCapacity;
	};

	class ToolBuilding : public MilitaryBuilding {
	public:
		ToolBuilding(const assets::MilitaryBuilding &provider, Animator &animator) : MilitaryBuilding(provider, animator) 
		{
			inUse=false;
		}

		void use() {
			inUse=true;
		}

		void finished() {
			inUse=false;
		}

		bool isAvailable() const {
			return !inUse;
		}

	protected:
		bool inUse;
	};


	class TrainingBuilding : public MilitaryBuilding {
	public:
		TrainingBuilding(bool isRanged, const assets::MilitaryBuilding &provider, Animator &animator) : MilitaryBuilding(provider, animator),
			mRanged(isRanged)
		{
			for(auto it=provider.usablePoints.begin();it!=provider.usablePoints.end();++it) {
				available.push_back(*it);
			}
		}

		bool ranged() const {
			return mRanged;
		}

		bool melee() const {
			return !mRanged;
		}

		bool isAvailable() const {
			return available.size()!=0;
		}

		gge::utils::Point allocate() {
			if(!available.size())
				throw std::runtime_error("No available slot");

			auto p=available.back();
			inUse.push_back(p);
			available.pop_back();

			return p+location;
		}

		void release(gge::utils::Point where) {
			where-=location;
			for(auto it=inUse.begin();it!=inUse.end();++it) {
				if(*it==where) {
					available.push_back(*it);
					inUse.erase(it);
					break;
				}
			}
		}


	protected:
		bool mRanged;

		std::vector<gge::utils::Point> available;
		std::vector<gge::utils::Point> inUse;
	};


}
