package net.angrycoding.cli.util;


import java.util.LinkedList;
import java.util.List;

import net.angrycoding.cli.command.Command;
import net.angrycoding.cli.command.CommandDescriptor;
import net.angrycoding.cli.util.Tree.Node;

public class CommandTree 
{
	private Tree<CommandDescriptor> commandTree = new Tree<CommandDescriptor>(null);
	
	private Node<CommandDescriptor> getNodeAtPath(String path) throws PathNotFoundException
	{
		String[] parts = path.split("/");
		if(!path.equals("/") && path.substring(path.length() - 1).equals("/"))
		{
			path = path.substring(0, path.length() - 1);
		}
		Node<CommandDescriptor> root = commandTree.getRoot();
		int depthCount = 0;
		for(String part : parts)
		{
			if(part == null || part.length() < 1)
				continue; //part will be null with leading slash
			
			List<Node<CommandDescriptor>> nodeList = commandTree.getChildrenAtLevel(root);
			if(nodeList != null)
			{
				for(Node<CommandDescriptor> n : nodeList)
				{
					if(n.data.cmdName.equals(part))
					{
						root = n;
						depthCount++;
					}
				}
			}
			
			if((StringUtil.countInstance(path, "/") - depthCount) > 1 && nodeList != null && !nodeList.isEmpty())
			{
				throw new PathNotFoundException(path);
			}
		}
		
		return root;
	}
	
	
	public void addCommandAtPath(String path, CommandDescriptor c) throws PathNotFoundException
	{
		commandTree.attachAtLevel(c, getNodeAtPath(path));
	}
	
	public Command getCommandAtPath(String path) throws PathNotFoundException
	{
		return getNodeAtPath(path).data.cmd;
	}
	
	public boolean hasChildrenAtPath(String path) throws PathNotFoundException
	{
		Node<CommandDescriptor> n = getNodeAtPath(path);
		return n.hasChildren();
	}
	public void dump()
	{
		dump(commandTree.getRoot(), "");
	}
	
	private void dump(Node<CommandDescriptor> node, String path)
	{	
		if(path.length() > 0)
			System.out.println(path);
		
		path += "/";
		List<Node<CommandDescriptor>> l = commandTree.getChildrenAtLevel(node);
		
		for(Node<CommandDescriptor> c : l)
		{
			dump(c, path + c.data.cmdName);
		}
		
	}


	public void addGlobalCommand(CommandDescriptor c) 
	{
		addGlobalCommand("/", c);
	}
	
	private void addGlobalCommand(String path, CommandDescriptor c)
	{
		try 
		{
			Node<CommandDescriptor> n = getNodeAtPath(path);
			if(n.hasChildren())
			{
				List<Node<CommandDescriptor>> children = n.getChildren();
				addCommandAtPath(path, c);
			
				for(Node<CommandDescriptor> child : children)
				{
					if(!child.data.equals(c))
						addGlobalCommand(path + child.data.cmdName + "/", c); //In some cases, we may have already been added. Skip over ourselves.
				}
			}
		} 
		catch (PathNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
	
	public List<CommandDescriptor> findCommandsAtPath(String path) throws PathNotFoundException
	{
		LinkedList<CommandDescriptor> ret = new LinkedList<CommandDescriptor>();
		
		Node<CommandDescriptor> root = getNodeAtPath(path);
	
		List<Node<CommandDescriptor>> nodeList = commandTree.getChildrenAtLevel(root);
		if(nodeList != null)
		{
			for(Node<CommandDescriptor> node : nodeList)
				ret.add(node.data);
		}
		
		return ret;
	}
	
	public List<CommandDescriptor> findCompletionsAtPath(String path, String completion) throws PathNotFoundException
	{
		LinkedList<CommandDescriptor> ret = new LinkedList<CommandDescriptor>();
		
		
		Node<CommandDescriptor> root = getNodeAtPath(path);
	
		List<Node<CommandDescriptor>> nodeList = commandTree.getChildrenAtLevel(root);
		if(nodeList != null)
		{
			for(Node<CommandDescriptor> node : nodeList)
			{
				if(node.data.cmdName.startsWith(completion))
					ret.add(node.data);
			}
				
		}
		
		return ret;
	}


	public CommandDescriptor getCommandDescriptorAtPath(String path) throws PathNotFoundException 
	{
		return getNodeAtPath(path).data;
	}
}
