// ----------------------------------------------------------------------------
//
//  Copyright (c) Microsoft Corporation.  All rights reserved.
//
// ----------------------------------------------------------------------------

namespace AppReader
{
    using System;
    using System.Collections;
    using System.Diagnostics;
    using System.IO;

	public class AppTree
	{
		AppNode top;
		public AppTree(AppNode top)
		{
			this.top = top;
		}

		public AppTree(AppTree other)
		{
			// we just walk the other tree and get a new copy
			this.top = other.top.Copy(null);
		}

		public void IncrementNode(string treePath)
		{
			IncrementNode(treePath, 1);
			return;
		}

		public void IncrementWithHashtable(Hashtable whash)
		{
			// a hashtable of paths in the tree and the weights of their endpoints
			// we just walk through the things we found and increment them in the tree
			// if they exist in the wxvals hashtable
			IEnumerator ienum = whash.GetEnumerator();
			while (ienum.MoveNext())
			{
				string key = (string)((DictionaryEntry)ienum.Current).Key;
				int val = (int)((DictionaryEntry)ienum.Current).Value;
				this.IncrementNode(key, val);
			}
			return;
		}

		public void Dump()
		{
			if (top != null)
			{
				Console.WriteLine("\nAppTree");
				top.Dump("");
			}
			return;
		}

		// this method converts a tree to a representation over which we can do clustering.
		// We add the sum of the weights of the children to the weight of their parent
		// so that we preserve the tree structure in the data, and then we do a post-order
		// traversal of the tree to get our ArrayList of weights.  It is thus critical that
		// all trees have the same structure and order, but our code guarantees this property.
		public ArrayList Flatten()
		{
			ArrayList ar = new ArrayList();
			AppTree treeToFlatten = new AppTree(this);
			treeToFlatten.top.Weight();
			treeToFlatten.top.Flatten(ar);
			return ar;
		}

		public void IncrementNode(string treePath, int count)
		{
			// HACK: 10 is a magic number.  I just don't think 
			// my resource trees will ever be 10 deep
			string[] pathstr = treePath.Split(new char[] {' '}, 10);
			AppNode curNode = top;
			for (int i = 0; i < pathstr.Length; i++)
			{
				if (pathstr[i].Equals("")) continue;
				// find the child that has the right name
				bool found = false;
				for (int j = 0; j < curNode.NumChildren; j++)
				{
					if (curNode[j].Name == pathstr[i])
					{
						curNode = curNode[j];
						found = true;
						break;
					}
				}
				Debug.Assert(found);
			}
			curNode.Increment(count);
			return;
		}

		public static AppTree CreateAppTree(string filename)
		{
			// parse the app tree structure here
			StreamReader ios = new StreamReader(filename);
			string curLine;
			// this is the first node we create
			AppNode top = null;
			AppNode lastNode = null;
			int lastTabCount = 0;
			while ((curLine = ios.ReadLine()) != null)
			{
				int tabcount = curLine.LastIndexOf("\t");
				tabcount++;
				//Console.WriteLine("Got tabcount {0}", tabcount);
				Debug.Assert(tabcount >= 0);

				string name = curLine.Substring(tabcount);
				AppNode parent = lastNode == null ? null : lastNode.Parent;
				if (tabcount < lastTabCount)
				{
					// then walk up the tree to the new parent
					int diff = lastTabCount - tabcount;
					while (diff-- > 0)
					{
						parent = parent.Parent;
						Debug.Assert(parent != null);
					}
				}
				else if (tabcount > lastTabCount) {
					parent = lastNode;
					Debug.Assert(tabcount == lastTabCount + 1);
				}
				// this automatically joins this node to its parent in the tree
				AppNode tempNode = new AppNode(name, parent);
				if (top == null)
				{
					Debug.Assert(tabcount == 0);
					top = tempNode;
				}
				lastNode = tempNode;
				lastTabCount = tabcount;
			}	
			AppTree outtree = new AppTree(top);
			return outtree;
		}
	}

}
