using System;
using System.Collections;
using System.Collections.Specialized;

namespace SemWeb.Util {
	internal class UriMap : IDictionary {
		private static char[] splitchars = { '\\', '/', '#' };
	
		Node Root;
		int count;
		
		public UriMap() {
			Clear();
		}
		
		bool ICollection.IsSynchronized { get { return false; } }
		object ICollection.SyncRoot { get { return null; } }

		bool IDictionary.IsFixedSize { get { return false; } }
		bool IDictionary.IsReadOnly { get { return false; } }		
		
		object IDictionary.this[object key] {
			get {
				return this[(string)key];
			}
			set {
				this[(string)key] = value;
			}
		}
		
		void IDictionary.Add(object key, object value) {
			this[(string)key] = value;
		}
		
		bool IDictionary.Contains(object key) {
			return Contains((string)key);
		}

		ICollection IDictionary.Keys { get { throw new NotImplementedException(); } }
		ICollection IDictionary.Values { get { throw new NotImplementedException(); } }
		IDictionaryEnumerator IDictionary.GetEnumerator() { throw new NotImplementedException(); }
		
		void IDictionary.Remove(object key) {
			Remove((string)key);
		}
		
		void ICollection.CopyTo(Array dest, int index) { throw new NotImplementedException(); }

		IEnumerator IEnumerable.GetEnumerator() { throw new NotImplementedException(); }
					
		public object this[string uri] {
			get {
				Node node = FindNode(uri, false);
				if (node == null) return null;
				return node.Value;
			}
			set {
				Node node = FindNode(uri, true);
				node.Value = value;
			}
		}
		
		public void Clear() {
			Root = new Node();
			count = 0;
		}
		
		public bool Contains(string uri) {
			Node node = FindNode(uri, false);
			return node != null;
		}
		
		public int Count { get { return count; } }
		
		Node FindNode(string uri, bool create) {
			Node node = Root;
			int pos; string piece;			
			NextPieceStart(out pos);
			while ((piece = NextPiece(uri, ref pos)) != null) {
				bool created;
				node = node.FindChild(piece, create, out created);
				if (created) count++;
				if (node == null) return null;
			}
			
			return node;
		}
		
		public void Remove(string uri) {
			Node node = Root;
			
			int pos;			
			NextPieceStart(out pos);
			string piece = NextPiece(uri, ref pos);
			string next = NextPiece(uri, ref pos);
			while (piece != null) {
				if (next != null) {
					bool created;
					node = node.FindChild(piece, false, out created);
					if (node == null) return;
				} else {
					if (node.RemoveChild(piece))
						count--;
				}
				piece = next;
				next = NextPiece(uri, ref pos);
			}
		}
		
		void NextPieceStart(out int position) {
			position = 0;
		}
		
		string NextPiece(string uri, ref int position) {
			if (position == uri.Length) return null;
			
			// Get the next stopping position
			int look = position;
			if (position == 0 && uri.Length > 15) look = 15;
			int next = uri.IndexOfAny(splitchars, look);
			if (next == -1) {
				string r = uri.Substring(position);
				position = uri.Length;
				return r;
			}
			
			// Grab sequences of the same character in a row.
			while (next != uri.Length-1 && uri[next] == uri[next+1])
				next++;
				
			string ret = uri.Substring(position, next-position+1);
			position = next+1;
			
			return ret;
		}
	
		private class Node {
			public IDictionary Children;
			public object Value;
			
			public Node FindChild(string name, bool create, out bool created) {
				if (Children == null && !create) {
					created = false;
					return null;
				}
				
				if (Children == null)
					Children = new HybridDictionary();
				
				Node ret = (Node)Children[name];
				if (ret != null || !create) {
					created = false;
					return ret;
				} else {
					created = true;
					ret = new Node();
					Children[name] = ret;
					return ret;
				}
			}
			
			public bool RemoveChild(string name) {
				if (Children != null && Children.Contains(name)) {
					Children.Remove(name);
					return true;
				}
				return false;
			}
			
		}
	}
}
