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

package engine.net.client.handlers;

import engine.InterestManagement.WorldGrid;
import engine.gameManager.ChatManager;
import engine.gameManager.DispatchManager;
import engine.gameManager.PowersManager;
import engine.mbEnums;
import engine.mbEnums.DispatchChannel;
import engine.net.Dispatch;
import engine.net.client.ClientConnection;
import engine.net.client.msg.ClientNetMsg;
import engine.net.client.msg.TrackWindowMsg;
import engine.objects.*;
import engine.powers.ActionsBase;
import engine.powers.PowersBase;
import engine.powers.RangeBasedAwo;
import engine.powers.poweractions.AbstractPowerAction;
import engine.powers.poweractions.TrackPowerAction;
import engine.server.MBServerStatics;
import org.pmw.tinylog.Logger;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;

public class TrackWindowMsgHandler extends AbstractClientMsgHandler {

    public TrackWindowMsgHandler() {
        super();
    }

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

        PlayerCharacter playerCharacter = origin.getPlayerCharacter();

        // Member variable declaration

        TrackWindowMsg msg;

        // Member variable assignment

        msg = (TrackWindowMsg) baseMsg;

        if (playerCharacter == null)
            return true;

        if (MBServerStatics.POWERS_DEBUG) {
            ChatManager.chatSayInfo(
                    playerCharacter,
                    "Using Power: " + Integer.toHexString(msg.getPowerToken())
                            + " (" + msg.getPowerToken() + ')');
            Logger.info("Using Power: "
                    + Integer.toHexString(msg.getPowerToken()) + " ("
                    + msg.getPowerToken() + ')');
        }

        // get track power used

        PowersBase pb = PowersManager.powersBaseByToken.get(msg.getPowerToken());

        if (pb == null || !pb.isTrack())
            return true;

        //check track threshold timer to prevent spam

        long currentTime = System.currentTimeMillis();
        long timestamp = playerCharacter.getTimeStamp("trackWindow");
        long dif = currentTime - timestamp;

        if (dif < MBServerStatics.TRACK_WINDOW_THRESHOLD)
            return true;

        playerCharacter.setTimeStamp("trackWindow", currentTime);

        ArrayList<ActionsBase> ablist = pb.getActions();

        if (ablist == null)
            return true;

        TrackPowerAction tpa = null;

        for (ActionsBase ab : ablist) {
            AbstractPowerAction apa = ab.getPowerAction();
            if (apa != null && apa instanceof TrackPowerAction)
                tpa = (TrackPowerAction) apa;
        }

        if (tpa == null)
            return true;

        // Check powers for normal users
        if (playerCharacter.getPowers() == null || !playerCharacter.getPowers().containsKey(msg.getPowerToken()))
            if (!playerCharacter.isCSR())
                if (!MBServerStatics.POWERS_DEBUG) {
                    //  ChatManager.chatSayInfo(pc, "You may not cast that spell!");
                    //  this.logEXPLOIT("usePowerA(): Cheat attempted? '" + msg.getPowerToken() + "' was not associated with " + pc.getName());
                    return true;
                }

        // Get search mask for track

        int mask = 0;

        if (pb.targetPlayer())
            if (tpa.trackVampire()) // track vampires
                mask = MBServerStatics.MASK_PLAYER | MBServerStatics.MASK_UNDEAD;
            else
                // track all players
                mask = MBServerStatics.MASK_PLAYER;
        else if (pb.targetCorpse()) // track corpses
            mask = MBServerStatics.MASK_CORPSE;
        else if (tpa.trackNPC()) // Track NPCs
            mask = MBServerStatics.MASK_NPC;
        else if (tpa.trackUndead()) // Track Undead
            mask = MBServerStatics.MASK_MOB | MBServerStatics.MASK_UNDEAD;
        else
            // Track All
            mask = MBServerStatics.MASK_MOB | MBServerStatics.MASK_NPC;

        // Find characters in range

        HashSet<AbstractWorldObject> allTargets;
        allTargets = WorldGrid.getObjectsInRangeContains(playerCharacter.getLoc(),
                pb.getRange(), mask);

        //remove anyone who can't be tracked

        Iterator<AbstractWorldObject> it = allTargets.iterator();

        while (it.hasNext()) {
            AbstractWorldObject awo = it.next();

            if (awo == null)
                continue;

            else if (!awo.isAlive())
                it.remove();

            else if (awo.getObjectType().equals(mbEnums.GameObjectType.PlayerCharacter)) {
                PlayerBonuses bonus = ((PlayerCharacter) awo).getBonuses();

                if (bonus != null && bonus.getBool(mbEnums.ModType.CannotTrack, mbEnums.SourceType.None))
                    it.remove();
            }
        }

        // get max characters for window

        int maxTargets = 20;
        PromotionClass promo = playerCharacter.getPromotionClass();

        if (promo != null) {
            int tableID = promo.getObjectUUID();
            if (tableID == 2512 || tableID == 2514 || tableID == 2515)
                maxTargets = 40;
        }

        // create list of characters
        HashSet<AbstractCharacter> trackChars = RangeBasedAwo.getTrackList(
                allTargets, playerCharacter, maxTargets);

        TrackWindowMsg trackWindowMsg = new TrackWindowMsg(msg);

        // send track window
        trackWindowMsg.setSource(playerCharacter);
        trackWindowMsg.setCharacters(trackChars);

        Dispatch dispatch = Dispatch.borrow(playerCharacter, trackWindowMsg);
        DispatchManager.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY);

        return true;
    }

}