#include "Townsfolk.h"
#include "PlayerGame.h"
#include "Soldier.h"
#include <Utils/Margins.h>

namespace mechanics {
	Townsfolk::Townsfolk(Animator &base, Animator &hair, Animator &cloth, Gender::Type given_gender) :
		Human(base, hair, OwnerType::player, given_gender),
			animatorCloth(cloth)
	{
		DecideStats();

		mLastSocialCheck=currentGameTime-gge::utils::Random(0, MINUTE);
		mNextAction=currentGameTime+gge::utils::Random(assets::constants::general::wanderRange.value,assets::constants::general::wanderRange.range);//!const

		Direction dir = (Direction)gge::utils::Random(0,4);
		Object::animator.setAnimation (dir, "Stand");

		Human::animatorHair.setAnimation (dir, "Stand");	
		cloth.setAnimation(dir, "Stand");
	}

	void Townsfolk::locateTo(const gge::utils::Point &given_location) {
		Human::locateTo(given_location);

		Direction dir = (Direction)gge::utils::Random(0,4);
		// base animator inherited from object
		Object::animator.setAnimation (dir, "Stand");
		Human::animatorHair.setAnimation (dir, "Stand");	
		animatorCloth.setAnimation(dir, "Stand");
	}

	unsigned Townsfolk::lastSocialCheck() const {
		return mLastSocialCheck;
	}

	void Townsfolk::lastSocialCheck(unsigned value) {
		mLastSocialCheck = value;
	}

	void Townsfolk::setAnimation(Direction direction, std::string animationID, bool isLooping, float speed) {
		Object::animator.setAnimation(direction, animationID, isLooping, speed);
		Human::animatorHair.setAnimation(direction, animationID, isLooping, speed);
		animatorCloth.setAnimation(direction, animationID, isLooping, speed);
	}

	void Townsfolk::setDirection(Direction direction, std::string animationID) {
		Object::animator.setDirection(direction, animationID);
		Human::animatorHair.setDirection(direction, animationID);
		animatorCloth.setDirection(direction, animationID);
	}

	void Townsfolk::Killed(Attacker *attacker, BaseWeapon *weapon) {
		Human::Killed(attacker, weapon);

		PlayerGame::current().AddToGameLog(name()+" "+surname()+" killed.");

		cancelMovement();

		PlayerGame::current().killTownsfolk(this);

		Map::current().getPointInfoMap()(location).walkable=true;
		Map::current().getPointInfoMap()(location).object=NULL;
	}

	void Townsfolk::checkAction() {
		if(!isAlive()) return;

		if(isMoving()) return;

		Human::checkAction();

		if(currentGameTime>mNextAction) {
			mNextAction=currentGameTime+gge::utils::Random(30000,120000);//!const

			int action=gge::utils::Random(0,2);
			switch(action) {
			case 1: {
				auto point=gge::utils::Random(PlayerGame::current().getTownBounds());
				while(!Map::current().getPointInfoMap()(point).walkable)
					point=gge::utils::Random(PlayerGame::current().getTownBounds());

				moveTo(point, PlayerGame::current().getTownBounds()+gge::utils::Margins(assets::constants::general::pathingLimitMargin));
				break;
					}
			default:
				;
			}
		}
	}

	void Townsfolk::DecideStats() {
		int totalodds=0;
		for(auto it = assets::Townfolks::list.begin();it!=assets::Townfolks::list.end();++it) {
			totalodds+=it->second->odds;
		}
		int r=gge::utils::Random(0, totalodds);
		auto it = assets::Townfolks::list.begin();
		for(;it!=assets::Townfolks::list.end();++it) {
			r-=it->second->odds;
			if(r<=0)
				break;
		}		

		assets::Townfolks stattemplate=*(it->second);
		float stats=stattemplate.totalStats.random();

		Stat statBase;
		if(mGender == Gender::male) {
			statBase = assets::constants::human::maleStats;
		}
		else {
			statBase = assets::constants::human::femaleStats;
		}

		mStat.str = stats*statBase.str / assets::constants::human::statDenominator;
		mStat.dex = stats*statBase.dex / assets::constants::human::statDenominator;
		mStat.acc = stats*statBase.acc / assets::constants::human::statDenominator;
		mStat.spe = stats*statBase.spe / assets::constants::human::statDenominator;
		mStat.intl= stats*statBase.intl/ assets::constants::human::statDenominator;
		mStat.vit = stats*statBase.vit / assets::constants::human::statDenominator;

		for(int i=0;i < 10;i++) {
			int random1 = gge::utils::Random(0, 6);
			int random2 = (random1 + gge::utils::Random(0, 5)) % 6;
			if(mStat.stats[random1]>assets::constants::stats::maxStat || mStat.stats[random2]<assets::constants::stats::minStat)
				continue;
			mStat.stats[random1] += 1;
			mStat.stats[random2] -= 1;
		}
	}

	Soldier *Townsfolk::BecomeASoldier() {
		if(!PlayerGame::current().ConsumeGold(assets::constants::gold::soldierGoldCost)) {
			std::stringstream ss;
			ss << "not enough gold. requires " << assets::constants::gold::soldierGoldCost << ".";
			PlayerGame::current().AddToGameLog(ss);
			return false;
		}

		cancelMovement();
		removeFromMap();
		PlayerGame::current().destroyTownsfolk(this);

		Soldier &soldier=*new Soldier(*this);
		PlayerGame::current().addSoldier(soldier);
		soldier.locateTo(location);
		//soldier.setAnimation(South, "Stand");

		//delete &animatorCloth;
		delete this;

		std::stringstream ss;
		ss << soldier.title() << " has become a soldier in exchange of " << assets::constants::gold::soldierGoldCost << " gold.";
		PlayerGame::current().AddToGameLog(ss);

		return &soldier;
	}

	Artisan *Townsfolk::BecomeAnArtisan(const std::string &type) {
		if(!PlayerGame::current().ConsumeGold(assets::constants::gold::artisanGoldCost)) {
			std::stringstream ss;
			ss << "not enough coins. requires " << assets::constants::gold::artisanGoldCost << ".";
			PlayerGame::current().AddToGameLog(ss);
			return false;
		}

		cancelMovement();
		removeFromMap();
		PlayerGame::current().destroyTownsfolk(this);

		Artisan &artisan=*new Artisan(*this, type, animatorCloth);
		PlayerGame::current().addArtisan(artisan);
		artisan.locateTo(location);
		//artisan.setAnimation(South, "Stand");

		delete this;

		std::stringstream ss;
		ss << artisan.title() << " has become an artisan in exchange of " << assets::constants::gold::artisanGoldCost << " gold.";
		PlayerGame::current().AddToGameLog(ss);

		return &artisan;
	}

}
