package ncrashed.warp.api.volume;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.logging.Logger;

import ncrashed.warp.IntVec3;
import ncrashed.warp.WarpMod;
import ncrashed.warp.api.IWarpCore;
import net.minecraft.entity.Entity;
import net.minecraft.util.AxisAlignedBB;
import net.minecraft.world.World;

public class SimpleVolume implements IVolume
{
	protected boolean setuped = false;
	protected List<IntVec3> markers;
	protected AxisAlignedBB box;
	protected final int MARKER_ID;
	
	public SimpleVolume(int markerId)
	{
		MARKER_ID = markerId;
		markers = new CopyOnWriteArrayList<IntVec3>();
		box = AxisAlignedBB.getBoundingBox(0, 0, 0, 0, 0, 0);
	}

	protected void updateBox()
	{
		box = AxisAlignedBB.getBoundingBox(0, 0, 0, 0, 0, 0);
		
		ListIterator<IntVec3> iter = markers.listIterator();
		while(iter.hasNext())
		{
			IntVec3 vec = iter.next();
			shrinkBox(box, vec.x, vec.y, vec.z, 0, 0, 0);
		}
	}
	
	@Override
	public boolean addMarker(World world, int x, int y, int z, int ox, int oy, int oz)
	{
		x = x-ox; 
		y = y-oy; 
		z = z-oz;
		
		ListIterator<IntVec3> iter = markers.listIterator();
		while(iter.hasNext())
		{
			IntVec3 vec = iter.next();
			if(vec.x == x && vec.y == y && vec.z == z)
			{
				return false;
			}
		}

		if(!isVecInsideBox(box, x, y, z))
		{
			shrinkBox(box, x, y, z, 0, 0, 0);
			markers.add(new IntVec3(x, y, z));
		}
		return false;
	}

	@Override
	public boolean removeMarker(World world, int x, int y, int z, int ox, int oy, int oz)
	{
		x = x-ox; 
		y = y-oy; 
		z = z-oz;
		System.out.println("Removing marker at " + x + "," + y + "," + z);
		
		ListIterator<IntVec3> iter = markers.listIterator();
		List<IntVec3> toRemove = new ArrayList<IntVec3>();
		while(iter.hasNext())
		{
			IntVec3 vec = iter.next();
			System.out.println("Checking marker:" + vec.x + "," + vec.y + "," + vec.z);
			if(vec.x == x && vec.y == y && vec.z == z)
			{
				toRemove.add(vec);
			}
		}
		
		if(toRemove.size() > 0)
		{
			markers.removeAll(toRemove);
			updateBox();
			return true;
		}
		
		return false;
	}
	
	@Override
	public boolean isValidVolume(World world, int ox, int oy, int oz, int maxsize, int minsx, int minsy, int minsz) 
	{	
		if(box.maxX-box.minX < minsx || box.maxY-box.minY < minsy || box.maxZ-box.minZ < minsz)
		{
			return false;
		}
		
		if(box.maxX-box.minX > maxsize || box.maxY-box.minY > maxsize || box.maxZ-box.minZ > maxsize)
		{
			return false;
		}
		
		return true;
	}


	@Override
	public boolean isVolumeSetuped() 
	{
		return setuped;
	}

	@Override
	public AxisAlignedBB getBoundingBox(int ox, int oy, int oz) 
	{
		AxisAlignedBB shiftedBox = box.copy();
		shiftedBox.minX += ox-2; shiftedBox.maxX += ox+2;
		shiftedBox.minY += oy-2; shiftedBox.maxY += oy+2;
		shiftedBox.minZ += oz-2; shiftedBox.maxZ += oz+2;
		return shiftedBox;
	}
	
	@Override
	public List<AxisAlignedBB> getBoxes(int ox, int oy, int oz) 
	{
		ArrayList<AxisAlignedBB> list = new ArrayList<AxisAlignedBB>();
		list.add(getBoundingBox(ox, oy, oz));
		return list;
	}
	
	private boolean listContainsCoords(List<IntVec3> list, int x, int y, int z)
	{
		for(int i = 0; i<list.size(); i++)
		{
			IntVec3 vec = list.get(i);
			if(vec.x == x && vec.y == y && vec.z == z) return true;
		}
		return false;
	}
	
	private boolean isVecInsideBox(AxisAlignedBB box, int x, int y, int z)
	{
		return x >= box.minX && x <= box.maxX && y >= box.minY && y <= box.maxY && z >= box.minZ && z <= box.maxZ;
	}
	
	private void shrinkBox(AxisAlignedBB box, int x, int y, int z, int ox, int oy, int oz)
	{
		if(x < box.minX && x < ox)
		{
			box.minX = x;
		} else if(x > box.maxX && x > ox)
		{
			box.maxX = x;
		}
		
		if(y < box.minY && y < oy)
		{
			box.minY = y;
		} else if(y > box.maxY && y > oy)
		{
			box.maxY = y;
		}
		
		if(z < box.minZ && z < oz)
		{
			box.minZ = z;
		} else if(z > box.maxZ && z > oz)
		{
			box.maxZ = z;
		}
	}

	@Override
	public List<IntVec3> getMarkers() 
	{
		return markers;
	}

	@Override
	public boolean setupVolume(List<IntVec3> markerList) 
	{
		markers.clear();
		ListIterator<IntVec3> iter = markers.listIterator();
		while(iter.hasNext())
		{
			IntVec3 vec = iter.next();
			addMarker(null, vec.x, vec.y, vec.z, 0, 0, 0);
		}
		
		return true;
	}

	@Override
	public boolean isEntityInside(World world, int ox, int oy, int oz,
			Entity ent) 
	{
		if(!world.equals(ent.worldObj)) return false;
		return ent.posX >= box.minX+ox-2 && ent.posX <= box.maxX+ox+2 && ent.posY >= box.minY+oy-2 && ent.posY <= box.maxY+oy+2 && ent.posZ >= box.minZ+oz-2 && ent.posZ <= box.maxZ+oz+2;
	}

	@Override
	public List<IWarpCore> getAnotherCores(World world, int ox, int oy, int oz) 
	{
		List<IWarpCore> cores = WarpMod.mRegister.getCoresInBox(world, 
				AxisAlignedBB.getBoundingBox(box.minX+ox, box.minY+oy, box.minZ+oz, box.maxX+ox, box.maxY+oy, box.maxZ+oz),
				false);
		
		for(int i = 0; i < cores.size(); ++i)
		{
			IWarpCore core = cores.get(i);
			if(core.getCoreX() == ox && core.getCoreY() == oy && core.getCoreZ() == oz)
			{
				cores.remove(i);
			}
		}
		
		return cores;
	}
}
