import java.io.Serializable;
import java.util.*;

/**
 * A binary tree in linked representation. Tree nodes are stored as objects consisting of
 * pointers to their left and right child and to their associated data.
 *
 * @param <A> The type of the data held in nodes of the tree.
 */
public class LinkedBinaryTree<A> implements BinaryTree<A> {

	public class LinkedNode<Datatype> {
		
		private Datatype 				m_data = null;
		private LinkedNode<Datatype>	m_leftleaf = null;
		private LinkedNode<Datatype>	m_rightleaf = null;
		
		public LinkedNode(Datatype data)
		{
			this.m_data = data;
		}
		
		public LinkedNode(Datatype data, LinkedNode<Datatype> leftleaf, LinkedNode<Datatype> rightleaf)
		{
			this.m_data = data;
			this.m_leftleaf = leftleaf;
			this.m_rightleaf = rightleaf;
		}

		public Datatype getData() {
			return m_data;
		}

		public void setData(Datatype data) {
			m_data = data;
		}

		public LinkedNode<Datatype> getLeftleaf() {
			return m_leftleaf;
		}

		public void setLeftleaf(LinkedNode<Datatype> leftleaf) {
			m_leftleaf = leftleaf;
		}

		public LinkedNode<Datatype> getRightleaf() {
			return m_rightleaf;
		}

		public void setRightleaf(LinkedNode<Datatype> rightleaf) {
			m_rightleaf = rightleaf;
		}
	}
	
	private LinkedNode<A> root = null;
	
	public static final Serializable clone(Serializable src)
	{
	try {
	java.io.ByteArrayOutputStream baos = new java.io.ByteArrayOutputStream();
	java.io.ObjectOutputStream oos = new java.io.ObjectOutputStream(baos);
	oos.writeObject(src);
	oos.flush();
	oos.close();
	java.io.ByteArrayInputStream bais = new
	java.io.ByteArrayInputStream(baos.toByteArray());
	java.io.ObjectInputStream ois = new java.io.ObjectInputStream(bais);
	Object dest = ois.readObject();
	ois.close();
	return (Serializable)dest;
	} catch (Throwable th) { return src; }
	}
	
	public static final String QUESTIONMARK = "?";
	
	/**
	 * Create a tree from a given animal game preorder. 
	 * 
	 * @param <B> The type of the data held in nodes of the tree.
	 * @param preorder The preorder to build the tree from.
	 * @return A new LinkedBinaryTree corresponding to the provided preorder.
	 */
	public static LinkedBinaryTree<String> createFromPreorder(List<String> preorder) {
		
		Vector<String> preordercopy = new Vector<String>();
		
		for(int i=0;i<preorder.size();i++)
		{
			preordercopy.add((String) clone(preorder.get(i)));
		}
		
		LinkedBinaryTree<String> result = new LinkedBinaryTree<String>();
		
		result.setRoot(result.recursiv_createFromPreorder(preordercopy));
		
		if(result.getRoot() == null)
			throw new UnsupportedOperationException();
		
		// TODO: Implement
		
		
		return result;
		
		//throw new UnsupportedOperationException();
	}
	
	private LinkedNode<A> getRoot() {
		return this.root;
	}

	private void setRoot(LinkedNode<A> root) {
		this.root = root; 
	}

	public LinkedNode<String> recursiv_createFromPreorder(List<String> preorder)
	{
		if(	preorder.size() < 1)// ||
			return null;
		
		//TODO
		LinkedNode<String> node = new LinkedNode<String>(preorder.get(0));
		
		preorder.remove(0);
		
		if(preorder.size() > 0){
			if(preorder.get(0).contains(QUESTIONMARK)) {
				node.setLeftleaf(recursiv_createFromPreorder(preorder));
			} else {
				node.setLeftleaf(new LinkedNode<String>(preorder.get(0)));
				preorder.remove(0);
			}
		}
		
		if(preorder.size() > 0){
			if(preorder.get(0).contains(QUESTIONMARK))
			{
				node.setRightleaf(recursiv_createFromPreorder(preorder));
			} else
			{
				node.setRightleaf(new LinkedNode<String>(preorder.get(0)));
				preorder.remove(0);
			}
		}
		
		return node;
	}

	/**
	 * Create a pre-order traversal sequence for this tree.
	 * 
	 * @return The pre-order sequence for this tree.
	 */
	@Override
	public List<A> preorder() {
		// TODO: Implement
		throw new UnsupportedOperationException();
	}

	@Override
	public BinaryTreeSearch<A> binaryTreeSearch() {
		// Create anonymous class implementing BinaryTreeSearch
		return new BinaryTreeSearch<A>() {
			
			@Override
			public A getData() {
				// TODO: Implement
				throw new UnsupportedOperationException();
			}

			@Override
			public boolean isLeaf() {
				// TODO: Implement
				throw new UnsupportedOperationException();
			}

			@Override
			public void nextLeftChild() {
				// TODO: Implement
				throw new UnsupportedOperationException();
			}

			@Override
			public void nextRightChild() {
				// TODO: Implement
				throw new UnsupportedOperationException();
			}

			@Override
			public void setNode(A data, A leftData, A rightData) {
				// TODO: Implement
				throw new UnsupportedOperationException();
			}

			@Override
			public boolean hasLeftChild() {
				// TODO: Implement
				throw new UnsupportedOperationException();
			}

			@Override
			public boolean hasRightChild() {
				// TODO: Implement
				throw new UnsupportedOperationException();
			}			
		};
	}

}
