package pneumaticCraft.common.ai;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import net.minecraft.entity.ai.EntityAIBase;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.ChunkPosition;
import pneumaticCraft.api.item.IProgrammable;
import pneumaticCraft.common.progwidgets.IProgWidget;
import pneumaticCraft.common.progwidgets.ProgWidgetExternalProgram;
import pneumaticCraft.common.tileentity.TileEntityProgrammer;
import pneumaticCraft.common.util.IOHelper;

public class DroneAIExternalProgram extends DroneAIBlockInteraction<ProgWidgetExternalProgram>{

    private final DroneAIManager subAI, mainAI;
    private final Set<ChunkPosition> traversedPositions = new HashSet<ChunkPosition>();
    private int curSlot;
    private NBTTagCompound curProgramTag; //Used to see if changes have been made to the program while running it.

    public DroneAIExternalProgram(IDroneBase drone, DroneAIManager mainAI, ProgWidgetExternalProgram widget){
        super(drone, widget);
        this.mainAI = mainAI;
        subAI = new DroneAIManager(drone, new ArrayList<IProgWidget>());
    }

    @Override
    public boolean shouldExecute(){
        if(super.shouldExecute()) {
            traversedPositions.clear();
            return true;
        } else {
            return false;
        }
    }

    @Override
    protected boolean moveToPositions(){
        return false;
    }

    @Override
    protected boolean isValidPosition(ChunkPosition pos){
        if(traversedPositions.add(pos)) {
            curSlot = 0;
            TileEntity te = drone.getWorld().getTileEntity(pos.chunkPosX, pos.chunkPosY, pos.chunkPosZ);
            return te instanceof IInventory;
        }
        return false;
    }

    @Override
    protected boolean doBlockInteraction(ChunkPosition pos, double distToBlock){
        IInventory inv = IOHelper.getInventoryForTE(drone.getWorld().getTileEntity(pos.chunkPosX, pos.chunkPosY, pos.chunkPosZ));
        if(inv == null) return false;
        if(curProgramTag != null) {
            if(curSlot < inv.getSizeInventory()) {
                ItemStack stack = inv.getStackInSlot(curSlot);
                if(stack != null && curProgramTag.equals(stack.getTagCompound())) {
                    subAI.onUpdateTasks();
                    if(subAI.isIdling() || isRunningSameProgram(subAI.getCurrentAI())) {
                        curProgramTag = null;
                        curSlot++;
                    }
                } else {
                    curProgramTag = null;
                    subAI.setWidgets(new ArrayList<IProgWidget>());
                }
            }
            return true;
        } else {
            while(curSlot < inv.getSizeInventory()) {
                ItemStack stack = inv.getStackInSlot(curSlot);
                if(stack != null && stack.getItem() instanceof IProgrammable) {
                    IProgrammable programmable = (IProgrammable)stack.getItem();
                    if(programmable.canProgram(stack) && programmable.usesPieces(stack)) {
                        List<IProgWidget> widgets = TileEntityProgrammer.getProgWidgets(stack);

                        boolean areWidgetsValid = true;
                        for(IProgWidget widget : widgets) {
                            if(!drone.isProgramApplicable(widget)) {
                                areWidgetsValid = false;
                                break;
                            }
                        }

                        if(areWidgetsValid) {
                            if(widget.shareVariables) mainAI.connectVariables(subAI);
                            subAI.getDrone().getAIManager().setLabel("Main");
                            subAI.setWidgets(widgets);
                            curProgramTag = stack.getTagCompound();
                            if(!subAI.isIdling()) {
                                return true;
                            }
                        }
                    }
                }
                curSlot++;
            }
            return false;
        }
    }

    //Prevent a memory leak, as a result of the same External program recursively calling itself.
    private boolean isRunningSameProgram(EntityAIBase ai){
        return ai instanceof DroneAIExternalProgram && curProgramTag.equals(((DroneAIExternalProgram)ai).curProgramTag);
    }

    public DroneAIManager getRunningAI(){
        return subAI;
    }

}