package ncrashed.warp.cores;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

import cpw.mods.fml.common.FMLCommonHandler;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import ncrashed.warp.CoreRegistry;
import ncrashed.warp.WarpMod;
import ncrashed.warp.api.IMarker;
import ncrashed.warp.api.IWarpCore;
import ncrashed.warp.api.volume.IVolume;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.AxisAlignedBB;

public class TileMarker extends TileEntity implements IMarker
{
	public static final int BINDING_EVENT = 1;
	
	private List<IWarpCore> warpCores;
	private int[] initCoreIDs;
	private int bindSyncTicker = 0;
	private int initialDelay = 100;
	private boolean wasUnloaded = false;
	private boolean wasInited = false;
	
	private boolean isBinded = false;
	private Side side;
	
	public TileMarker()
	{
		warpCores = new CopyOnWriteArrayList<IWarpCore>();
		side = FMLCommonHandler.instance().getEffectiveSide();
	}
	
	@Override
	public void updateEntity() 
	{
		if(side == Side.SERVER)
		{
			if(worldObj == null) return;
			
			if(initialDelay > 0)
			{
				--initialDelay;
				return;
			}
			
			if(initCoreIDs != null && (!wasInited || wasUnloaded))
			{
				for(int i = 0; i < initCoreIDs.length; i++)
				{
					tryBindCore(WarpMod.mRegister.getCoreByID(this.worldObj, initCoreIDs[i]));
				}
				
				wasInited = true;
				wasUnloaded = false;
				
			} else if(warpCores.size() == 0 && wasInited)
			{
				IWarpCore core = WarpMod.mRegister.getClosestCore(worldObj, xCoord, yCoord, zCoord, IVolume.MAX_MARKER_DIST, true);
				if(core == null) return;
				
				tryBindCore(core);
			}
			
			if(++bindSyncTicker > 150)
			{	
				findIncompliteCoreAndBind();
				
				worldObj.addBlockEvent(xCoord, yCoord, zCoord, WarpMod.mMarkerBlock.blockID, BINDING_EVENT, isBinded() ? 1 : 0);
				bindSyncTicker = 0;
			}
			
		}
	}
	
	public void findIncompliteCoreAndBind()
	{
		List<IWarpCore> cores = WarpMod.mRegister.getCoresInBox(worldObj,
				AxisAlignedBB.getBoundingBox(
						xCoord-IVolume.MAX_MARKER_DIST, 0, zCoord-IVolume.MAX_MARKER_DIST, 
						xCoord+IVolume.MAX_MARKER_DIST, 255, zCoord+IVolume.MAX_MARKER_DIST),
				true);
		
		Iterator<IWarpCore> iter = cores.iterator();
		while(iter.hasNext())
		{
			IWarpCore core = iter.next();
			if(!warpCores.contains(core))
			{
				tryBindCore(core);
			}
		}
	}
	
	@Override
	@SideOnly(Side.CLIENT)
	public void receiveClientEvent(int eventID, int eventPar) 
	{
		if(eventID == BINDING_EVENT)
		{
			isBinded = eventPar == 1;
		}
	}
	
	@Override
	public void tryBindCore(IWarpCore core)
	{
		if(warpCores.contains(core)) return;
		
		warpCores.add(core);
		core.getCoreVolume().addMarker(worldObj, xCoord, yCoord, zCoord, core.getCoreX(), core.getCoreY(), core.getCoreZ());
		core.checkConstruction();
		
		Iterator<IWarpCore> iter = warpCores.iterator();
		while(iter.hasNext())
		{
			IWarpCore chCore = iter.next();
			if(chCore == null || chCore.isInvalid())
			{
				warpCores.remove(chCore);
				System.out.println("Ubinded marker core");
			}
		}
		
		if(warpCores.size() == 0)
		{
			worldObj.addBlockEvent(xCoord, yCoord, zCoord, WarpMod.mMarkerBlock.blockID, BINDING_EVENT, 0);
		} else
		{
			System.out.println("Successfully binded marker to core with id "+core.getCoreID());
			worldObj.addBlockEvent(xCoord, yCoord, zCoord, WarpMod.mMarkerBlock.blockID, BINDING_EVENT, 1);
		}
	}
	
    /**
     * Reads a tile entity from NBT.
     */
	@Override
    public void readFromNBT(NBTTagCompound tagCompound)
    {
        super.readFromNBT(tagCompound);
        Side side = FMLCommonHandler.instance().getEffectiveSide();
        if(side == Side.SERVER)
        {
        	warpCores.clear();
        	initCoreIDs = tagCompound.getIntArray("CoresID");
	        System.out.println("Loaded marker " + initCoreIDs.toString());
        }
    }

    /**
     * Writes a tile entity to NBT.
     */
	@Override
    public void writeToNBT(NBTTagCompound tagCompound)
    {
        super.writeToNBT(tagCompound);
        
        Side side = FMLCommonHandler.instance().getEffectiveSide();
        if(side == Side.SERVER)
        {
        	int[] ids = new int[warpCores.size()];
        	for(int i = 0; i < warpCores.size(); i++)
        	{
        		ids[i] = warpCores.get(i).getCoreID();
        	}
        	
        	tagCompound.setIntArray("CoresID", ids);
        }
    }
	
	@Override
	public void onChunkUnload()
	{
		wasUnloaded = true;
	}

	@Override
	public List<IWarpCore> getBindedCores() 
	{
		return warpCores;
	}

	@Override
	public boolean isBinded() 
	{
		if(side.equals(Side.CLIENT))
		{
			return isBinded;
		} else
		{
			return warpCores.size() > 0;
		}
	}

	@Override
	public int getCoresCount() 
	{
		return warpCores.size();
	}
}
