// • ▌ ▄ ·.  ▄▄▄·  ▄▄ • ▪   ▄▄· ▄▄▄▄·  ▄▄▄·  ▐▄▄▄  ▄▄▄ .
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
// ▀▀  █▪▀▀▀ ▀  ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀  ▀  ▀ ▀▀  █▪ ▀▀▀
//      Magicbane Emulator Project © 2013 - 2022
//                www.magicbane.com


package engine.net.client.handlers;

import engine.Enum.DispatchChannel;
import engine.exception.MsgSendException;
import engine.net.DispatchMessage;
import engine.net.client.ClientConnection;
import engine.net.client.msg.ChangeAltitudeMsg;
import engine.net.client.msg.ClientNetMsg;
import engine.objects.AbstractCharacter;
import engine.objects.Building;
import engine.objects.PlayerCharacter;
import engine.objects.Regions;
import engine.server.MBServerStatics;
import org.pmw.tinylog.Logger;

public class ChangeAltitudeHandler extends AbstractClientMsgHandler {

    public ChangeAltitudeHandler() {
        super(ChangeAltitudeMsg.class);
    }

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

        ChangeAltitudeMsg msg = (ChangeAltitudeMsg) baseMsg;

        PlayerCharacter pc = origin.getPlayerCharacter();
        if (pc == null) {
            return false;
        }

        if (!AbstractCharacter.CanFly(pc))
            return false;

        if (pc.isSwimming())
            return false;
        if (pc.region != null && !pc.region.isOutside())
            return false;


        // Find out if we already have an altitude timer running and if so
        // do not process more alt change requests

        if (pc.getTakeOffTime() != 0)
            return false;


        // remove all movement timers and jobs
        //TODO: test if they can fly

        float targetAlt;
        float amount = msg.getAmountToMove();
        if (amount != 10 && amount != 60)
            return false;
        if (pc.getAltitude() == 60 && msg.up())
            return true;
        if (pc.getAltitude() == 0 && !msg.up())
            return true;

        pc.update();
        pc.stopMovement(pc.getLoc());
        msg.setStartAlt(pc.getAltitude());
        if (msg.up()) {

            pc.landingRegion = null;
            if (pc.getAltitude() == 0) {
                Regions upRegion = pc.region;
                if (upRegion != null) {
                    float startAlt = 0;
                    Building regionBuilding = Regions.GetBuildingForRegion(upRegion);
                    if (upRegion != null)
                        startAlt = upRegion.lerpY(pc) - regionBuilding.getLoc().y;
                    float rounded = startAlt * .10f;

                    rounded = ((int) rounded) * 10;

                    if (rounded < 0)
                        rounded = 0;


                    msg.setStartAlt(startAlt);
                    targetAlt = rounded + amount;

                    if (targetAlt > 60)
                        targetAlt = 60;

                    pc.setAltitude(startAlt);
                    pc.setDesiredAltitude(targetAlt);
                } else {
                    msg.setStartAlt(pc.getAltitude());
                    targetAlt = pc.getAltitude() + amount;
                    if (targetAlt > 60)
                        targetAlt = 60;
                }
            } else {
                msg.setStartAlt(pc.getAltitude());

                targetAlt = pc.getAltitude() + amount;
                if (targetAlt > 60)
                    targetAlt = 60;
            }


        } else {
            msg.setStartAlt(pc.getAltitude());
            targetAlt = pc.getAltitude() - amount;
            if (targetAlt < 0)
                targetAlt = 0;
        }
        msg.setTargetAlt(targetAlt);
        if (pc.getAltitude() < 1 && targetAlt > pc.getAltitude()) {
            // char is on the ground and is about to start flight
            if (pc.getStamina() < 10) {
                return false;
            }
        }

        if (MBServerStatics.MOVEMENT_SYNC_DEBUG) {
            Logger.info("Changing Altitude, moving=" + pc.isMoving() +
                    " Current Loc " + pc.getLoc().getX() + ' ' + pc.getLoc().getZ() +
                    " End Loc " + pc.getEndLoc().getX() + ' ' + pc.getEndLoc().getZ());
        }

        if (msg.up()) {
            pc.update();
            pc.setDesiredAltitude(targetAlt);
            pc.setTakeOffTime(System.currentTimeMillis());
        } else {
            Regions region = PlayerCharacter.InsideBuildingRegionGoingDown(pc);


            if (region != null) {
                float landingAltitude = 0;
                Building building = Regions.GetBuildingForRegion(region);
                if (building != null)
                    landingAltitude = region.lerpY(pc) - building.getLoc().y;

                if (landingAltitude >= targetAlt) {
                    pc.landingRegion = region;
                    pc.landingAltitude = landingAltitude;
                    pc.setDesiredAltitude(landingAltitude);
                } else {
                    pc.landingRegion = null;
                    pc.setDesiredAltitude(targetAlt);
                }


            } else
                pc.setDesiredAltitude(targetAlt);

            pc.update();


            pc.setTakeOffTime(System.currentTimeMillis());
        }


        // Add timer for height change cooldown, this also tells getLoc we are not moving
        //MovementManager.addChangeAltitudeTimer(pc, msg.getStartAlt(), msg.getTargetAlt(), (int)((MBServerStatics.HEIGHT_CHANGE_TIMER_MS * amount) + 100 )  );

        // Add flight timer job to check stam and ground you when you run out
        //MovementManager.addFlightTimer(pc, msg, MBServerStatics.FLY_FREQUENCY_MS);
        //Send change altitude to all in range
        DispatchMessage.dispatchMsgToInterestArea(pc, msg, DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, true, false);


        return true;
    }

}
