package atomicstryker.minions.common.jobmanager;

import java.util.ArrayList;

import atomicstryker.minions.common.MinionsCore;

import net.minecraft.src.Block;
import net.minecraft.src.ChunkCoordIntPair;
import net.minecraft.src.ChunkCoordinates;
import net.minecraft.src.Material;
import net.minecraft.src.World;

/**
 * Minion Mod Runnable Tree Scanner class. Finds Trees in a certain area around a first given Tree, returns a List once done.
 * 
 * 
 * @author AtomicStryker
 */

public class TreeScanner implements Runnable
{
	private Minion_Job_TreeHarvest boss;
	private ChunkCoordinates startCoords;
	private World worldObj;
	private int foundTreeCount = 0;
	private int currentX;
	private int currentZ;
	private int currentMaxX = 0;
	private int currentMaxZ = 0;
	private int treeBlockID;
	private ArrayList<ChunkCoordIntPair> skippableCoords = new ArrayList();
	
	public TreeScanner(Minion_Job_TreeHarvest creator)
	{
		boss = creator;
	}

	public void setup(ChunkCoordinates coords, World worldObj)
	{
		startCoords = coords;
		currentX = coords.posX;
		currentZ = coords.posZ;
		this.worldObj = worldObj;
	}

	@Override
	public void run()
	{
		//System.out.println("AS_TreeScanner starting to run at ["+currentX+"|"+currentZ+"]");
		boolean otherDirection = false;
		while (foundTreeCount < 16 && currentMaxX < 64)
		{
			// iterate length X
			int nextXStop = currentX + (otherDirection ? currentMaxX * -1 : currentMaxX);
			while (currentX != nextXStop)
			{
				checkForTreeAtCoords();
				if (otherDirection)
				{
					currentX--;
				}
				else
				{
					currentX++;
				}
			}
			// iterate length Z
			int nextZStop = currentZ + (otherDirection ? currentMaxZ * -1 : currentMaxZ);
			while (currentZ != nextZStop)
			{
				checkForTreeAtCoords();
				if (otherDirection)
				{
					currentZ--;
				}
				else
				{
					currentZ++;
				}
			}
			
			// change movement direction as per search algorithm
			otherDirection = !otherDirection;
			
			// expand lengths for next run
			currentMaxX++;
			currentMaxZ++;
		}
		
		//System.out.println("AS_TreeScanner finished work, found: "+foundTreeCount+"; checked length: "+currentMaxX);
		boss.onDoneFindingTrees();
	}
	
	private void checkForTreeAtCoords()
	{
		if (skippableCoords.contains(new ChunkCoordIntPair(currentX, currentZ))) // to fix more-than-1-block-thick trees
		{
			return;
		}
		
		//System.out.println("checkForTreeAtCoords ["+currentX+"|"+currentZ+"]");
		int y = this.worldObj.getTopSolidOrLiquidBlock(currentX, currentZ);
		if (y != -1)
		{
			int ID = this.worldObj.getBlockId(currentX, y-1, currentZ);
			if (MinionsCore.foundTreeBlocks.contains(ID))
			{
				int newID;
				for (;(newID = this.worldObj.getBlockId(currentX, --y, currentZ)) == ID;)
				{
				}
				
				if (newID == 0 || Block.blocksList[newID].blockMaterial == Material.leaves)
				{
					return;
				}
				else
				{
					onFoundTreeBase(currentX, y+1, currentZ);
				}
			}
		}
		Thread.yield();
	}
	
	private void onFoundTreeBase(int ix, int iy, int iz)
	{
		for (int jx = -1; jx <= 1; jx++)
		{
			for (int jz = -1; jz <= 1; jz++)
			{
				ChunkCoordIntPair excludeCoords = new ChunkCoordIntPair(ix+jx, iz+jz);
				if (!skippableCoords.contains(excludeCoords))
				{
					skippableCoords.add(excludeCoords);
				}
			}
		}
		
	    ArrayList<ChunkCoordinates> treeBlockList = new ArrayList();
	    ArrayList<ChunkCoordinates> leaveBlockList = new ArrayList();
	    treeBlockID = this.worldObj.getBlockId(ix, iy, iz);
	    indexTargetTree(ix, iy, iz, treeBlockList, leaveBlockList);
		
	    if (treeBlockList.size() > 3)
		{
	    	foundTreeCount++;
	    	boss.onFoundTreeBase(ix, iy, iz, treeBlockList, leaveBlockList);
		}
	}
	
    private void indexTargetTree(int ix, int iy, int iz, ArrayList<ChunkCoordinates> treeBlockList, ArrayList<ChunkCoordinates> leaveBlockList)
    {
    	indexTreeBlockRecursive(ix, iy, iz, treeBlockList, leaveBlockList);
    }
    
    private void indexTreeBlockRecursive(int ix, int iy, int iz, ArrayList<ChunkCoordinates> treeBlockList, ArrayList<ChunkCoordinates> leaveBlockList)
    {
        byte one = 1;
        for (int xIter = -one; xIter <= one; xIter++)
        {
            for (int zIter = -one; zIter <= one; zIter++)
            {
                for (int yIter = 0; yIter <= one; yIter++)
                {
                    if (worldObj.getBlockId(ix + xIter, iy + yIter, iz + zIter) == treeBlockID)
                    {
                    	ChunkCoordinates coords = new ChunkCoordinates(ix + xIter, iy + yIter, iz + zIter);
                    	if (!treeBlockList.contains(coords))
                    	{
                    		treeBlockList.add(coords);
                    		findLeavesRecursive(ix + xIter, iy + yIter, iz + zIter, 0, leaveBlockList);
                    		indexTreeBlockRecursive(ix + xIter, iy + yIter, iz + zIter, treeBlockList, leaveBlockList);
                    	}
                    }
                }
            }
        }
    }
    
    private void findLeavesRecursive(int ix, int iy, int iz, int fromStem, ArrayList<ChunkCoordinates> leaveBlockList)
    {
        byte one = 1;
        for (int xIter = -one; xIter <= one; xIter++)
        {
            for (int zIter = -one; zIter <= one; zIter++)
            {
                for (int yIter = 0; yIter <= one; yIter++)
                {
                	if (worldObj.getBlockMaterial(ix + xIter, iy + yIter, iz + zIter) == Material.leaves)
                    {
                    	if (fromStem < 4)
                    	{
                        	ChunkCoordinates coords = new ChunkCoordinates(ix + xIter, iy + yIter, iz + zIter);
                        	if (!leaveBlockList.contains(coords))
                        	{
                        		leaveBlockList.add(coords);
                        		findLeavesRecursive(ix + xIter, iy + yIter, iz + zIter, fromStem+1, leaveBlockList);
                        	}
                    	}
                    }
                }
            }
        }
    }
}