package engine.net.client.handlers;

import engine.Enum;
import engine.Enum.BuildingGroup;
import engine.Enum.GuildState;
import engine.exception.MsgSendException;
import engine.gameManager.*;
import engine.net.client.ClientConnection;
import engine.net.client.msg.AbandonAssetMsg;
import engine.net.client.msg.ClientNetMsg;
import engine.net.client.msg.ErrorPopupMsg;
import engine.objects.*;
import org.pmw.tinylog.Logger;

/*
 * @Author:
 * @Summary: Processes application protocol message which processes
 * client requests to abandon a building.
 */
public class AbandonAssetMsgHandler extends AbstractClientMsgHandler {

	// Instance variables

	public AbandonAssetMsgHandler() {
		super(AbandonAssetMsg.class);

	}

	@Override
	protected boolean _handleNetMsg(ClientNetMsg baseMsg, ClientConnection origin) throws MsgSendException {

		// Member variable declaration
		PlayerCharacter player;
		Building building;
		AbandonAssetMsg msg;

		// Member variable assignment
		msg = (AbandonAssetMsg) baseMsg;

		player = origin.getPlayerCharacter();
		building = BuildingManager.getBuildingFromCache(msg.getUUID());

		// Oops!  *** Refactor: Log error
		if ((player == null) || (building == null))
			return true;

		// Early exit if object is not owned by the player
		if (building.getOwnerUUID() != player.getObjectUUID())
			return true;

		// Cannot abandon a building without a blueprint.
		// Players do not own rocks or shrubbery.
		if (building.getBlueprintUUID() == 0)
			return true;

		// Players cannot abandon shrines

		if ((building.getBlueprint().getBuildingGroup() == BuildingGroup.SHRINE)) {
			ErrorPopupMsg.sendErrorMsg(player, "Cannot for to abandon shrine!");
			return true;
		}

		if ((building.getBlueprint().getBuildingGroup() == BuildingGroup.MINE)) {
			ErrorPopupMsg.sendErrorMsg(player, "Cannot abandon mine!");
			return true;
		}

		if (Blueprint.isMeshWallPiece(building.getBlueprintUUID())) {
			ErrorPopupMsg.sendErrorMsg(player, "Cannot for to abandon fortress asset!");
			return true;
		}

		if ((building.getBlueprint().getBuildingGroup() == BuildingGroup.BARRACK)) {
			ErrorPopupMsg.sendErrorMsg(player, "Cannot for to abandon fortress asset!");
			return true;
		}

		if ((building.getBlueprint().getBuildingGroup() == BuildingGroup.BULWARK)) {
			ErrorPopupMsg.sendErrorMsg(player, "Cannot for to abandon siege asset!");
			return true;
		}

		if ((building.getBlueprint().getBuildingGroup() == BuildingGroup.SIEGETENT)) {
			ErrorPopupMsg.sendErrorMsg(player, "Cannot for to abandon siege asset!");
			return true;
		}

		if ((building.getBlueprint().getBuildingGroup() == BuildingGroup.BANESTONE)) {
			ErrorPopupMsg.sendErrorMsg(player, "Cannot for to abandon banestone!");
			return true;
		}

		// Trees require special handling beyond an individual building
		if ((building.getBlueprint().getBuildingGroup() == BuildingGroup.TOL))
		{
			// CHECK IF GUILD HAS A BANE DROPPED
			City city = ZoneManager.getCityAtLocation(building.getLoc());
			if(city.getGuild().getSubGuildList().isEmpty() == false)
			{
				//nations cant abandon their tree
				ErrorPopupMsg.sendErrorMsg(player, "Nations Cannot Abandon Their Capital!");
				return true;
			}
			if(Bane.getBaneByAttackerGuild(city.getGuild()) != null)
			{
				ErrorPopupMsg.sendErrorMsg(player, "You Cannot Abandon Your Tree With An Active Siege!");
				return true;
			}

			AbandonAllCityObjects(player, building);
		}
		else
			AbandonSingleAsset(player, building);

		return true;
	}

	private static void AbandonSingleAsset(PlayerCharacter sourcePlayer,
                                           Building targetBuilding) {

		// Transfer the building asset ownership and refresh all clients

		DbManager.BuildingQueries.CLEAR_FRIENDS_LIST(targetBuilding.getObjectUUID());
		targetBuilding.getFriends().clear();

		// Clear protection status but only if a seige building

        if (targetBuilding.getBlueprint().getBuildingGroup().equals(BuildingGroup.BULWARK) ||
			targetBuilding.getBlueprint().getBuildingGroup().equals(BuildingGroup.SIEGETENT))
				targetBuilding.setProtectionState(Enum.ProtectionState.NONE);

		DbManager.BuildingQueries.CLEAR_CONDEMNED_LIST(targetBuilding.getObjectUUID());
		targetBuilding.getCondemned().clear();
		targetBuilding.setOwner(null);
		targetBuilding.refreshGuild();

	}

	private void AbandonAllCityObjects(PlayerCharacter sourcePlayer,
			Building targetBuilding) {
		Guild sourceGuild;
		Zone cityZone;

		sourceGuild = sourcePlayer.getGuild();

		if (sourceGuild == null)
			return;

		if (sourceGuild.getSubGuildList().size() > 0) {
			ChatManager.chatCityError(sourcePlayer, "You Cannot abandon a nation city.");
			return;
		}
		
		

		cityZone = ZoneManager.findSmallestZone(targetBuilding.getLoc());

		// Can't abandon a tree not within a player city zone
		if (cityZone.isPlayerCity() == false)
			return;
		
		if (targetBuilding.getCity() == null)
			return;
		
		if (targetBuilding.getCity().getBane() != null){
			ErrorPopupMsg.sendErrorMsg(sourcePlayer, "Can't abandon Tree while a bane exists.");
			return;
		}

		if (targetBuilding.getCity().hasBeenTransfered == true) {
			ChatManager.chatCityError(sourcePlayer, "City can only be abandoned once per rebooting.");
			return;
		}

		// Guild no longer owns his tree.
		if (!DbManager.GuildQueries.SET_GUILD_OWNED_CITY(sourceGuild.getObjectUUID(), 0)) {
			Logger.error("Failed to update Owned City to Database");
			return;
		}

		sourceGuild.setCityUUID(0);
		sourceGuild.setGuildState(GuildState.Errant);
		sourceGuild.setNation(null);

		// Transfer the city assets
		TransferCityAssets(sourcePlayer, targetBuilding);

		GuildManager.updateAllGuildTags(sourceGuild);
		GuildManager.updateAllGuildBinds(sourceGuild, null);

	}

	private void TransferCityAssets(PlayerCharacter sourcePlayer,
			Building cityTOL) {

		Zone cityZone;

		// Build list of buildings within this parent zone
		cityZone = ZoneManager.findSmallestZone(cityTOL.getLoc());

		for (Building cityBuilding : cityZone.zoneBuildingSet) {

			Blueprint cityBlueprint;
			cityBlueprint = cityBuilding.getBlueprint();

			// Buildings without blueprints cannot be abandoned
			if (cityBlueprint == null)
				continue;

			// Transfer ownership of valid city assets
			if ((cityBlueprint.getBuildingGroup() == BuildingGroup.TOL)
					|| (cityBlueprint.getBuildingGroup() == BuildingGroup.SPIRE)
					|| (cityBlueprint.getBuildingGroup() == BuildingGroup.BARRACK)
					|| (cityBlueprint.isWallPiece())
					|| (cityBuilding.getBlueprint().getBuildingGroup() == BuildingGroup.SHRINE))
				AbandonSingleAsset(sourcePlayer, cityBuilding);

		}

	}

}