package engine.net.client.handlers;

import engine.Enum;
import engine.Enum.DispatchChannel;
import engine.Enum.GameObjectType;
import engine.exception.MsgSendException;
import engine.gameManager.BuildingManager;
import engine.gameManager.DbManager;
import engine.gameManager.SessionManager;
import engine.gameManager.ZoneManager;
import engine.math.Bounds;
import engine.net.Dispatch;
import engine.net.DispatchMessage;
import engine.net.client.ClientConnection;
import engine.net.client.msg.ClientNetMsg;
import engine.net.client.msg.ErrorPopupMsg;
import engine.net.client.msg.ManageCityAssetsMsg;
import engine.net.client.msg.PlaceAssetMsg;
import engine.objects.*;
import org.joda.time.DateTime;

/*
 * @Author:
 * @Summary: Processes application protocol message which opens
 * and processes the various building asset management windows.
 */
public class ManageCityAssetMsgHandler extends AbstractClientMsgHandler {

    public ManageCityAssetMsgHandler() {
        super(ManageCityAssetsMsg.class);
    }

    public static boolean playerCanManageNotFriends(PlayerCharacter player, Building building) {

        //Player Can only Control Building if player is in Same Guild as Building and is higher rank than IC.

        if (player == null)
            return false;

        if (building.getRank() == -1)
            return false;

        if (BuildingManager.IsOwner(building, player))
            return true;

        if (GuildStatusController.isGuildLeader(player.getGuildStatus()) == false && GuildStatusController.isInnerCouncil(player.getGuildStatus()) == false)
            return false;

        //Somehow guild leader check fails above? lets check if Player is true Guild GL.
        if (building.getGuild() != null && building.getGuild().isGuildLeader(player.getObjectUUID()))
            return true;

        return Guild.sameGuild(building.getGuild(), player.getGuild());

    }

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

        ManageCityAssetsMsg msg;
        PlayerCharacter player;
        ManageCityAssetsMsg outMsg;
        Building building;

        msg = (ManageCityAssetsMsg) baseMsg;
        player = SessionManager.getPlayerCharacter(origin);

        if (player == null)
            return true;

        building = BuildingManager.getBuildingFromCache(msg.getTargetID());

        if (building == null) {
            if (msg.actionType == 14) {
                Zone zone = ZoneManager.findSmallestZone(player.getLoc());
                if (!zone.isPlayerCity()) {
                    ErrorPopupMsg.sendErrorMsg(player, "Unable to find city to command.");
                    return true;
                }
                City city = City.GetCityFromCache(zone.getPlayerCityUUID());
                if (city == null || !city.getGuild().equals(player.getGuild()) ||
                        (!GuildStatusController.isInnerCouncil(player.getGuildStatus()) &&
                                !GuildStatusController.isGuildLeader(player.getGuildStatus()))) {
                    ErrorPopupMsg.sendErrorMsg(player, "You are not in the correct guild to command this city.");
                    return true;
                }
                ManageCityAssetsMsg mca = new ManageCityAssetsMsg(player, building);
                mca.actionType = 15;
                DispatchMessage.dispatchMsgDispatch(Dispatch.borrow(player, mca), DispatchChannel.SECONDARY);
            }
            return true;
        }

        outMsg = new ManageCityAssetsMsg(player, building);

        if (player.isSafeMode()) {
            outMsg.actionType = 4;
            outMsg.setTargetType(building.getObjectType().ordinal());
            outMsg.setTargetID(building.getObjectUUID());
            outMsg.setAssetName(building.getName());
            DispatchMessage.dispatchMsgDispatch(Dispatch.borrow(player, outMsg), DispatchChannel.SECONDARY);
            return true;
        }

        switch (msg.actionType) {
            case 2:
            case 22:
                if (building.getBlueprint() != null && building.getBlueprint().getBuildingGroup() == engine.Enum.BuildingGroup.BANESTONE) {
                    outMsg.actionType = 18;
                    outMsg.setTargetType(building.getObjectType().ordinal());
                    outMsg.setTargetID(building.getObjectUUID());
                } else if (BuildingManager.playerCanManage(player, building)) {
                    configWindowState(player, building, outMsg);
                    outMsg.actionType = 3;
                    outMsg.setTargetType(building.getObjectType().ordinal());
                    outMsg.setTargetID(building.getObjectUUID());
                    outMsg.setTargetType3(building.getObjectType().ordinal());
                    outMsg.setTargetID3(building.getObjectUUID());
                    outMsg.setUnknown54(1);
                } else {
                    // Handle other cases
                    if (building.getRank() == -1) {
                        if (!Bounds.collide(player.getLoc(), building)) {
                            ErrorPopupMsg.sendErrorPopup(player, 64);
                            return true;
                        }
                        switch (building.getBlueprint().getBuildingGroup()) {
                            case SHRINE:
                                Shrine shrine = Shrine.shrinesByBuildingUUID.get(building.getObjectUUID());
                                if (shrine == null || shrine.getFavors() == 0) {
                                    ErrorPopupMsg.sendErrorPopup(player, 166); // There is no more favor in this shrine to loot
                                    return true;
                                }
                                //loot elan stones
                                MobLoot elanStones = new MobLoot(player,ItemBase.getItemBase(1705032),1,false);
                                Item promotedItem = elanStones.promoteToItem(player);
                                promotedItem.setNumOfItems(shrine.getFavors());
                                player.getCharItemManager().addItemToInventory(promotedItem);
                                DbManager.ItemQueries.UPDATE_NUM_ITEMS(promotedItem,promotedItem.getNumOfItems(),1);
                                player.getCharItemManager().updateInventory();
                                shrine.setFavors(0);
                                break;
                            case WAREHOUSE:
                                Warehouse warehouse = Warehouse.warehouseByBuildingUUID.get(building.getObjectUUID());
                                if (warehouse == null || warehouse.isEmpty()) {
                                    ErrorPopupMsg.sendErrorPopup(player, 167); // no more resources.
                                    return true;
                                }
                                break;
                        }
                    }
                    AbstractCharacter owner = building.getOwner();
                    if (owner == null) {
                        msg.actionType = 4;
                        DispatchMessage.dispatchMsgDispatch(Dispatch.borrow(player, msg), DispatchChannel.SECONDARY);
                    } else {
                        outMsg.actionType = 4;
                        outMsg.setTargetType(building.getObjectType().ordinal());
                        outMsg.setTargetID(building.getObjectUUID());
                        outMsg.setAssetName(building.getName());
                    }
                }
                DispatchMessage.dispatchMsgDispatch(Dispatch.borrow(player, outMsg), DispatchChannel.SECONDARY);
                return true;
            case 13:
                outMsg.actionType = 13;
                DispatchMessage.dispatchMsgDispatch(Dispatch.borrow(player, outMsg), DispatchChannel.SECONDARY);
                return true;
            case 5:
                building.setName(msg.getAssetName());
                configWindowState(player, building, outMsg);
                outMsg.actionType = 3;
                outMsg.setTargetType(building.getObjectType().ordinal());
                outMsg.setTargetID(building.getObjectUUID());
                outMsg.setTargetType3(GameObjectType.Building.ordinal());
                outMsg.setTargetID3(building.getObjectUUID());
                outMsg.setAssetName1(building.getName());
                outMsg.setUnknown54(1);
                DispatchMessage.dispatchMsgDispatch(Dispatch.borrow(player, outMsg), DispatchChannel.SECONDARY);
                return true;
            case 14:
                ManageCityAssetsMsg mca = new ManageCityAssetsMsg(player, building);
                mca.actionType = 15;
                DispatchMessage.dispatchMsgDispatch(Dispatch.borrow(player, mca), DispatchChannel.SECONDARY);
                return true;
            case 20:
                // Handle case 20
                return handleCase20(player, outMsg, building, msg, origin);
            default:
                return true;
        }
    }

    private boolean handleCase20(PlayerCharacter player, ManageCityAssetsMsg outMsg, Building building, ManageCityAssetsMsg msg, ClientConnection origin) throws MsgSendException {
        Zone baneZone = building.getParentZone();
        if (baneZone == null)
            return true;
        City banedCity = City.getCity(baneZone.getPlayerCityUUID());
        if (banedCity == null)
            return true;
        Bane bane = banedCity.getBane();
        if (bane == null || bane.getLiveDate() != null || player.getGuild() != banedCity.getGuild() || !GuildStatusController.isInnerCouncil(player.getGuildStatus()))
            return true;
        int baneHour = msg.getBaneHour();
        if (baneHour < 16 || baneHour > 24) {
            PlaceAssetMsg.sendPlaceAssetError(origin, 1, "A Serious error has occurred. Please post details for to ensure transaction integrity");
            return true;
        }
        DateTime baneLive = new DateTime(bane.getPlacementDate());
        baneLive = baneHour == 24 ? baneLive.plusDays(3) : baneLive.plusDays(2);
        baneLive = baneHour == 24 ? baneLive.hourOfDay().setCopy(0) : baneLive.hourOfDay().setCopy(baneHour);
        baneLive = baneLive.minuteOfHour().setCopy(0);
        baneLive = baneLive.secondOfMinute().setCopy(1);
        bane.setLiveDate(baneLive);
        outMsg.actionType = 18;
        DispatchMessage.dispatchMsgDispatch(Dispatch.borrow(player, outMsg), DispatchChannel.SECONDARY);
        return true;
    }


    public void configWindowState(PlayerCharacter player, Building building, ManageCityAssetsMsg manageCityAssetsMsg) {

        // Tests to turn on upgrade button if a building is not
        // at it's maximum allowed rank or currently ranking


        // Owner is obviously allowed to upgrade his own buildings

        if (building.getOwner() != null && building.getOwner().equals(player)) {

            // Players cannot destroy or transfer a TOL.

            if (building.getBlueprint() == null) {
                manageCityAssetsMsg.buttonDestroy = 0;
                manageCityAssetsMsg.buttonTransfer = 0;
                manageCityAssetsMsg.buttonAbandon = 0;
                manageCityAssetsMsg.buttonUpgrade = 0;
            } else if (building.getBlueprint().getBuildingGroup() == Enum.BuildingGroup.TOL) {
                manageCityAssetsMsg.buttonDestroy = 0;
                manageCityAssetsMsg.buttonTransfer = 0;
                manageCityAssetsMsg.buttonAbandon = 1;
                manageCityAssetsMsg.buttonUpgrade = 1;
            } else if (building.getBlueprint().getBuildingGroup() == Enum.BuildingGroup.MINE) {
                manageCityAssetsMsg.buttonDestroy = 0;
                manageCityAssetsMsg.buttonTransfer = 0;
                manageCityAssetsMsg.buttonAbandon = 0;
                manageCityAssetsMsg.buttonUpgrade = 0;  // Cannot upgrade a mine
            } else {
                manageCityAssetsMsg.buttonDestroy = 1;
                manageCityAssetsMsg.buttonTransfer = 1;
                manageCityAssetsMsg.buttonAbandon = 1;
                manageCityAssetsMsg.buttonUpgrade = 1;
            }
        }

        // Inner Council of the same guild can also upgrade

        if ((player.getGuild().equals(building.getGuild())) &&
                GuildStatusController.isInnerCouncil(player.getGuildStatus()))
            manageCityAssetsMsg.buttonUpgrade = 1;

        // Disable upgrade button if at max rank.

        if (building.getBlueprint() == null)
            manageCityAssetsMsg.buttonUpgrade = 0;
        else if (building.getRank() >= building.getBlueprint().getMaxRank())
            manageCityAssetsMsg.buttonUpgrade = 0;
        ;

        // If a building is not protected we can exit here

        if (building.assetIsProtected() == false)
            return;

        // Protection is displayed as "UNDER SIEGE" if
        // an active bane is invalidating the protection
        // contracts of the city.

        if ((building.getCity() != null) &&
                (building.getCity().protectionEnforced == false)) {
            manageCityAssetsMsg.labelProtected = 0;
            manageCityAssetsMsg.labelSiege = 1;
            manageCityAssetsMsg.labelCeaseFire = 0;
            return;
        }

        // Building is currently protected by a TOL

        manageCityAssetsMsg.labelProtected = 1;
    }
}
