package pneumaticCraft.client.render.pneumaticArmor;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.ScaledResolution;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.monster.EntityMob;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.util.AxisAlignedBB;
import net.minecraft.util.EnumChatFormatting;
import net.minecraft.util.Vec3;
import net.minecraftforge.client.event.MouseEvent;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.common.config.Configuration;
import pneumaticCraft.api.client.pneumaticHelmet.EntityTrackEvent;
import pneumaticCraft.api.client.pneumaticHelmet.IOptionPage;
import pneumaticCraft.api.client.pneumaticHelmet.IUpgradeRenderHandler;
import pneumaticCraft.client.gui.pneumaticHelmet.GuiEntityTrackOptions;
import pneumaticCraft.client.gui.widget.GuiAnimatedStat;
import pneumaticCraft.common.CommonHUDHandler;
import pneumaticCraft.common.NBTUtil;
import pneumaticCraft.common.config.Config;
import pneumaticCraft.common.item.ItemMachineUpgrade;
import pneumaticCraft.common.item.Itemss;
import pneumaticCraft.common.util.PneumaticCraftUtils;
import pneumaticCraft.lib.PneumaticValues;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;

public class EntityTrackUpgradeHandler implements IUpgradeRenderHandler{

    private final List<RenderTarget> targets = new ArrayList<RenderTarget>();
    private final Map<Entity, Integer> targetingEntities = new HashMap<Entity, Integer>();
    private boolean shouldStopSpamOnEntityTracking = false;
    private static final int ENTITY_TRACK_THRESHOLD = 7;
    private static final float ENTITY_TRACKING_RANGE = 16F;
    public boolean gaveNotAbleToTrackEntityWarning;

    @SideOnly(Side.CLIENT)
    private GuiAnimatedStat entityTrackInfo;
    private int statX;
    private int statY;
    private boolean statLeftSided;
    public static String UPGRADE_NAME = "entityTracker";

    @Override
    @SideOnly(Side.CLIENT)
    public String getUpgradeName(){
        return UPGRADE_NAME;
    }

    @Override
    @SideOnly(Side.CLIENT)
    public void update(EntityPlayer player, int rangeUpgrades){
        ItemStack helmetStack = player.getCurrentArmor(3);
        String entityFilter = "";
        if(helmetStack != null) entityFilter = NBTUtil.getString(helmetStack, "entityFilter");
        double entityTrackRange = ENTITY_TRACKING_RANGE + rangeUpgrades * PneumaticValues.RANGE_UPGRADE_HELMET_RANGE_INCREASE;
        AxisAlignedBB bbBox = getAABBFromRange(player, rangeUpgrades);
        List<Entity> mobs = player.worldObj.getEntitiesWithinAABB(EntityLivingBase.class, bbBox);
        if(mobs.contains(player)) mobs.remove(player);
        for(int i = 0; i < mobs.size(); i++) {
            if(player.getDistanceToEntity(mobs.get(i)) > entityTrackRange || !PneumaticCraftUtils.isEntityValidForFilter(entityFilter, mobs.get(i)) || MinecraftForge.EVENT_BUS.post(new EntityTrackEvent(mobs.get(i)))) continue;
            boolean inList = false;
            for(int j = 0; j < targets.size(); j++) {
                if(targets.get(j).entity == mobs.get(i)) {
                    inList = true;
                    targets.get(j).ticksExisted = Math.abs(targets.get(j).ticksExisted);// cancel
                                                                                        // lost
                                                                                        // targets
                    break;
                }
            }
            if(!inList) {
                //player.worldObj.playSoundAtEntity(player, Sounds.CANNON_SOUND, 1.0F, 1.0F);
                targets.add(new RenderTarget(mobs.get(i)));
                if(mobs.get(i) instanceof EntityMob && !isEntityWithinPlayerFOV(player, mobs.get(i))) {
                    //       HUDHandler.instance().addMessage(new ArmorMessage("A mob is sneaking up on you!", new ArrayList<String>(), 60, 0x70FF0000));
                }
            }
        }
        for(int j = 0; j < targets.size(); j++) {
            RenderTarget target = targets.get(j);
            if(target.entity.isDead || player.getDistanceToEntity(target.entity) > entityTrackRange + 5 || !PneumaticCraftUtils.isEntityValidForFilter(entityFilter, target.entity)) {
                if(target.ticksExisted > 0) {
                    target.ticksExisted = -60;
                } else if(target.ticksExisted == -1) {
                    targets.remove(target);
                    j--;
                }
            }
        }
        if(targets.size() > ENTITY_TRACK_THRESHOLD) {
            if(!shouldStopSpamOnEntityTracking) {
                shouldStopSpamOnEntityTracking = true;
                HUDHandler.instance().addMessage(new ArmorMessage("Stopped spam on Entity Tracker", new ArrayList<String>(), 60, 0x7700AA00));
            }
        } else {
            shouldStopSpamOnEntityTracking = false;
        }
        List<String> text = new ArrayList<String>();
        for(RenderTarget target : targets) {
            boolean wasNegative = target.ticksExisted < 0;
            target.ticksExisted += CommonHUDHandler.getHandlerForPlayer(player).getSpeedFromUpgrades();
            if(target.ticksExisted >= 0 && wasNegative) target.ticksExisted = -1;
            target.update();
            if(target.isLookingAtTarget) {
                if(target.isInitialized()) {
                    text.add(EnumChatFormatting.GRAY + target.entity.getCommandSenderName());
                    text.addAll(target.getEntityText());
                } else {
                    text.add(EnumChatFormatting.GRAY + "Acquiring target...");
                }
            }
        }
        if(text.size() == 0) {
            text.add("Filter mode: " + (entityFilter.equals("") ? "None" : entityFilter));
        }
        entityTrackInfo.setText(text);

        //Remove entities that don't need to be tracked anymore.
        Iterator<Entry<Entity, Integer>> iterator = targetingEntities.entrySet().iterator();
        while(iterator.hasNext()) {
            Entry<Entity, Integer> entry = iterator.next();
            Entity entity = entry.getKey();
            if(entry.getValue() >= 0) entry.setValue(entry.getValue() + 1);
            if(entity.isDead || !player.worldObj.getLoadedEntityList().contains(entity) || entry.getValue() > 50) iterator.remove();
        }
    }

    public void warnIfNecessary(Entity entity){
        if(!targetingEntities.containsKey(entity)) {
            HUDHandler.instance().addMessage(new ArmorMessage("A mob is targeting you!", new ArrayList<String>(), 60, 0x70FF0000));
        }
        targetingEntities.put(entity, -1);
    }

    public void removeTargetingEntity(Entity entity){
        if(targetingEntities.containsKey(entity)) {
            targetingEntities.put(entity, 0);
        }
    }

    public static AxisAlignedBB getAABBFromRange(EntityPlayer player, int rangeUpgrades){
        double entityTrackRange = ENTITY_TRACKING_RANGE + Math.min(10, rangeUpgrades) * PneumaticValues.RANGE_UPGRADE_HELMET_RANGE_INCREASE;

        return AxisAlignedBB.getBoundingBox(player.posX - entityTrackRange, player.posY - entityTrackRange, player.posZ - entityTrackRange, player.posX + entityTrackRange, player.posY + entityTrackRange, player.posZ + entityTrackRange);
    }

    private boolean isEntityWithinPlayerFOV(EntityPlayer player, Entity entity){
        // code used from the Enderman player looking code.
        Vec3 vec3 = player.getLook(1.0F).normalize();
        Vec3 vec31 = Vec3.createVectorHelper(entity.posX - player.posX, entity.boundingBox.minY + entity.height / 2.0F - (player.posY + player.getEyeHeight()), entity.posZ - player.posZ);
        double d0 = vec31.lengthVector();
        vec31 = vec31.normalize();
        double d1 = vec3.dotProduct(vec31);
        return d1 > 1.0D - 2.5D / d0;
        // return d1 > 1.0D - 0.025D / d0;
    }

    @Override
    @SideOnly(Side.CLIENT)
    public void render3D(float partialTicks){
        for(RenderTarget target : targets) {
            target.render(partialTicks, shouldStopSpamOnEntityTracking);
        }
    }

    @Override
    @SideOnly(Side.CLIENT)
    public void render2D(float partialTicks, boolean upgradeEnabled){}

    @Override
    public boolean isEnabled(ItemStack[] upgradeStacks){
        for(ItemStack stack : upgradeStacks) {
            if(stack != null && stack.getItem() == Itemss.machineUpgrade && stack.getItemDamage() == ItemMachineUpgrade.UPGRADE_ENTITY_TRACKER) return true;
        }
        return false;
    }

    @Override
    @SideOnly(Side.CLIENT)
    public void reset(){
        targets.clear();
    }

    @Override
    public float getEnergyUsage(int rangeUpgrades, EntityPlayer player){
        return PneumaticValues.USAGE_ENTITY_TRACKER * (1 + (float)Math.min(10, rangeUpgrades) * PneumaticValues.RANGE_UPGRADE_HELMET_RANGE_INCREASE / ENTITY_TRACKING_RANGE) * CommonHUDHandler.getHandlerForPlayer(player).getSpeedFromUpgrades();
    }

    @Override
    @SideOnly(Side.CLIENT)
    public IOptionPage getGuiOptionsPage(){
        return new GuiEntityTrackOptions(this);
    }

    @Override
    public void initConfig(Configuration config){
        statX = config.get("Helmet_Options" + Configuration.CATEGORY_SPLITTER + "Entity_Tracker", "stat X", -1).getInt();
        statY = config.get("Helmet_Options" + Configuration.CATEGORY_SPLITTER + "Entity_Tracker", "stat Y", 90).getInt();
        statLeftSided = config.get("Helmet_Options" + Configuration.CATEGORY_SPLITTER + "Entity_Tracker", "stat leftsided", true).getBoolean(true);
    }

    @Override
    public void saveToConfig(){
        Configuration config = Config.config;
        config.load();
        config.get("Helmet_Options" + Configuration.CATEGORY_SPLITTER + "Entity_Tracker", "stat X", -1).set(entityTrackInfo.getBaseX());
        config.get("Helmet_Options" + Configuration.CATEGORY_SPLITTER + "Entity_Tracker", "stat Y", 90).set(entityTrackInfo.getBaseY());
        config.get("Helmet_Options" + Configuration.CATEGORY_SPLITTER + "Entity_Tracker", "stat leftsided", true).set(entityTrackInfo.isLeftSided());
        statX = entityTrackInfo.getBaseX();
        statY = entityTrackInfo.getBaseY();
        statLeftSided = entityTrackInfo.isLeftSided();
        config.save();
    }

    @Override
    @SideOnly(Side.CLIENT)
    public GuiAnimatedStat getAnimatedStat(){
        if(entityTrackInfo == null) {
            Minecraft minecraft = Minecraft.getMinecraft();
            ScaledResolution sr = new ScaledResolution(minecraft, minecraft.displayWidth, minecraft.displayHeight);
            entityTrackInfo = new GuiAnimatedStat(null, "Current tracked entities:", new ItemStack(Itemss.machineUpgrade, 1, ItemMachineUpgrade.UPGRADE_ENTITY_TRACKER), statX != -1 ? statX : sr.getScaledWidth() - 2, statY, 0x3000AA00, null, statLeftSided);
            entityTrackInfo.setMinDimensionsAndReset(0, 0);
        }
        return entityTrackInfo;

    }

    public List<RenderTarget> getTargets(){
        return targets;
    }

    public RenderTarget getTargetForEntity(Entity entity){
        for(RenderTarget target : targets) {
            if(target.entity == entity) {
                return target;
            }
        }
        return null;
    }

    public void hack(){
        for(RenderTarget target : targets) {
            target.hack();
        }
    }

    public boolean scroll(MouseEvent event){
        for(RenderTarget target : targets) {
            if(target.scroll(event)) return true;
        }
        return false;
    }

}
