#include "TownBuilding.h"
#include "PlayerGame.h"
#include <Widgets/Dialogs/Message.h>

namespace mechanics {
	void TownBuilding::setAreaBuildable() {
		auto mapsize=Map::current().getPointInfoMap().GetSize();

		int xmin=std::max(0, location.x-mBuildingArea);
		int xmax=std::min(mapsize.Width, location.x+this->provider().size.Width+mBuildingArea);

		int ymin=std::max(0, location.y-mBuildingArea);
		int ymax=std::min(mapsize.Height, location.y+this->provider().size.Height+mBuildingArea);

		bool isTownCenter = (provider().ID == "Town center");

		for(int y=ymin;y<ymax;y++) {
			for(int x=xmin;x<xmax;x++) {
				if((gge::utils::Point(x,y)-location).Distance()<mBuildingArea) {
					Map::current().getPointInfoMap()(x, y).buildable = true;
				}
			}
		}

		gge::utils::Bounds bounds = PlayerGame::current().getTownBounds();
		if(bounds.Left == -1 || bounds.Left > xmin) {
			bounds.Left = xmin;
		}

		if(bounds.Right == -1 || bounds.Right < xmax) {
			bounds.Right = xmax;
		}

		if(bounds.Top == -1 || bounds.Top > ymin) {
			bounds.Top = ymin;
		}

		if(bounds.Bottom == -1 || bounds.Bottom < ymax) {
			bounds.Bottom = ymax;
		}

		PlayerGame::current().setTownBounds(bounds);

		if(isTownCenter) {
			xmin=std::max(0, int(location.x-assets::constants::general::townCenterSight));
			xmax=std::min(mapsize.Width, int(location.x+this->provider().size.Width+assets::constants::general::townCenterSight));

			ymin=std::max(0, int(location.y-assets::constants::general::townCenterSight));
			ymax=std::min(mapsize.Height, int(location.y+this->provider().size.Height+assets::constants::general::townCenterSight));

			for(int y=ymin;y<ymax;y++) {
				for(int x=xmin;x<xmax;x++) {
					if((gge::utils::Point(x,y)-location).Distance()<assets::constants::general::townCenterSight) {
						Map::current().getPointInfoMap()(x, y).inSight = true;
						Map::current().getPointInfoMap()(x, y).revealed = true;
						Map::current().getPointInfoMap()(x, y).townCenter = true;
					}
				}
			}
		}
	}

	void TownBuilding::rebuildBuildableMap() {
		auto &objects = Map::current().getObjects();

		PlayerGame::current().setTownBounds(gge::utils::Bounds(-1,-1,-1,-1));
		Map::current().getPointInfoMap().ForAllCells([&](const gge::utils::Point &location, PointInfo &pointInfo) {
			pointInfo.buildable = false;
		});

		for(auto it = objects.First(); it.IsValid(); it.Next()) {
			TownBuilding *building = dynamic_cast<TownBuilding *>(it.CurrentPtr());

			if(building == NULL) {
				continue;
			}

			building->setAreaBuildable();
		}

		if(PlayerGame::current().getTownBounds()==gge::utils::Bounds(-1,-1,-1,-1)) {
			PlayerGame::current().endGame();
			gge::widgets::dialog::ShowMessage("Your town is destroyed.", "Game over");
		}
	}

	void TownBuilding::destroy() {
		mechanics::PlayerGame::current().destroyTownBuilding(*this);
		this->removeFromMap();
		delete this;
	}

	void TownBuilding::Killed(Attacker *attacker, BaseWeapon *weapon) {
		Attackable::Killed(attacker, weapon);
		PlayerGame::current().destroyTownBuilding(*this);

		removeFromMap();
	}

	void TownBuilding::locateTo(const gge::utils::Point &given_location) {
		Object::locateTo(given_location);

		if(mProvider.ID == "Town center") {
			PlayerGame::current().townCenterLoc(currentArea());
		}

		Object::setNonPassable(mProvider);
		setAreaBuildable();
	}

	void TownBuilding::setLocation(const gge::utils::Point &given_location) {
		if(given_location == location) {
			return;
		}

		Object::setPassable(mProvider);

		Object::setLocation(given_location);

		Object::setNonPassable(mProvider);


		if(mProvider.ID == "Town center") {
			mechanics::PlayerGame::current().townCenterLoc(currentArea());
		}

		rebuildBuildableMap();
	}

}