package com.planet_ink.coffee_mud.Libraries.layouts;
import java.util.*;

import com.planet_ink.coffee_mud.core.Directions;
import com.planet_ink.coffee_mud.Libraries.interfaces.AreaGenerationLibrary.LayoutFlags;
import com.planet_ink.coffee_mud.Libraries.interfaces.AreaGenerationLibrary.LayoutNode;
import com.planet_ink.coffee_mud.Libraries.interfaces.AreaGenerationLibrary.LayoutTypes;

public class TreeLayout extends AbstractLayout
{
	public String name(){return "TREE";}
	int originalDirection=Directions.NORTH;
	
	private class TreeStem
	{
		public LayoutNode currNode = null;
		private int dir = Directions.NORTH;
		private LayoutSet lSet = null;
		public TreeStem(long[] coord, int dir, LayoutSet d)
		{
			this.dir = dir;
			this.lSet = d;
			currNode = new DefaultLayoutNode(coord);
		}
		private long[] getCoord(long[] curr, int dir) { return lSet.makeNextCoord(curr,dir);}
		
		private int[] getTurns(int dir) 
		{ 
			switch(dir)
			{
			case Directions.NORTH:
			case Directions.SOUTH:
				if(originalDirection==Directions.EAST) return new int[]{Directions.EAST};
				if(originalDirection==Directions.WEST) return new int[]{Directions.WEST};
				return new int[]{Directions.WEST,Directions.EAST};
			case Directions.EAST:
			case Directions.WEST:
				if(originalDirection==Directions.NORTH) return new int[]{Directions.NORTH};
				if(originalDirection==Directions.SOUTH) return new int[]{Directions.SOUTH};
				return new int[]{Directions.NORTH,Directions.SOUTH};
			}
			return null;
		}
		
		public TreeStem nextNode() 
		{
			long[] nextCoord = getCoord(currNode.coord(),dir);
			TreeStem stem = new TreeStem(nextCoord,dir,lSet);
			if(!lSet.use(stem.currNode,LayoutTypes.street)) return null;
			currNode.crossLink(stem.currNode);
			patchRun(currNode,stem.currNode);
			return stem;
		}

		private void patchRun(LayoutNode from, LayoutNode to) {
			to.flagRun(AbstractLayout.getRunDirection(getDirection(from,to)));
		}
		
		public TreeStem firstBranch() {
			int[] turns = getTurns(dir);
			if((turns == null)||(turns.length<1)) return null;
			long[] nextCoord = getCoord(currNode.coord(),turns[0]);
			TreeStem newStem =  new TreeStem(nextCoord,turns[0],lSet);
			if(!lSet.use(newStem.currNode,LayoutTypes.street)) return null;
			currNode.flag(LayoutFlags.corner);
			currNode.crossLink(newStem.currNode);
			patchRun(currNode,newStem.currNode);
			return newStem;
		}
		public TreeStem secondBranch() {
			int[] turns = getTurns(dir);
			if((turns == null)||(turns.length<2)) return null;
			long[] nextCoord = getCoord(currNode.coord(),turns[1]);
			TreeStem newStem =  new TreeStem(nextCoord,turns[1],lSet);
			if(!lSet.use(newStem.currNode,LayoutTypes.street)) return null;
			currNode.crossLink(newStem.currNode);
			patchRun(currNode,newStem.currNode);
			return newStem;
		}
	}
	
	public Vector<LayoutNode> generate(int num, int dir) 
	{
		Vector<LayoutNode> set = new Vector<LayoutNode>();
		Vector<TreeStem> progress = new Vector<TreeStem>();
		
		long[] rootCoord = new long[]{0,0};
		LayoutSet lSet = new LayoutSet(set,num);
		originalDirection=dir;
		TreeStem root = new TreeStem(rootCoord, dir, lSet);
		progress.add(root);
		lSet.use(root.currNode,LayoutTypes.street);
		root.currNode.flag(LayoutFlags.gate);
		root.currNode.flagGateExit(dir);
		root.currNode.flagRun(AbstractLayout.getRunDirection(dir));
		
		while(lSet.spaceAvailable()) {
			Vector<TreeStem> newOnes = new Vector<TreeStem>();
			for(Iterator<TreeStem> i =  progress.iterator(); i.hasNext() && lSet.spaceAvailable(); )
			{
				TreeStem stem = i.next();
				TreeStem branch = stem.nextNode();
				if(branch != null) newOnes.add(branch);
				branch = stem.firstBranch();
				if(branch != null) newOnes.add(branch);
				branch = stem.secondBranch();
				if(branch != null) newOnes.add(branch);
			}
			progress = new Vector<TreeStem>();
			while(newOnes.size()> 0)
			{
				TreeStem b =  newOnes.elementAt(r.nextInt(newOnes.size()));
				progress.add(b);
				newOnes.remove(b);
			}
		}
		lSet.clipLongStreets();
		lSet.fillInFlags();
		return set;
	}
}
