/*
 * Bernoulli Compiler
 * Copyright (c) Cornell University
 * Department of Computer Science
 * 
 * Kamen Yotov (kamen@yotov.org)
 * 
 * $Source: C:/CVS/kyotov/kyotov/Research/BC/XTensions/Collections/Set.cs,v $
 * $Revision: 1.1 $
 * $Date: 2002/10/22 19:52:31 $
 */

using System;
using System.Collections;
using System.Diagnostics;
namespace XTensions
{
	namespace Collections
	{
		[Serializable]
		public class Set: ICollection, ICloneable
		{
			protected Hashtable S;

			public Set ()
			{
				S = new Hashtable();
			}

			public Set (object o) :
				this()
			{
				Add(o);
			}

			public int Count
			{
				get
				{
					return S.Count;
				}
			}

			public bool Empty
			{
				get
				{
					return Count == 0;
				}
			}

			public bool Contains (object o)
			{
				return S.Contains(o);
			}

			public void CopyTo (System.Array a, int i)
			{
				S.Keys.CopyTo(a, i);
			}

			public bool IsSynchronized
			{
				get
				{
					return S.Keys.IsSynchronized;
				}
			}

			public object SyncRoot
			{
				get
				{
					return S.Keys.SyncRoot;
				}
			}

			public void Add (object o)
			{
				S[o] = null;
			}

			public IEnumerator GetEnumerator ()
			{
				return S.Keys.GetEnumerator();
			}

			public object Clone ()
			{
				Set r = new Set();

				foreach (object o in this)
					r.Add(o);

				return r;
			}

			public static bool isNull (Set s)
			{
				return (object)s == null;
			}
		
			public object Singleton
			{
				get
				{
					Debug.Assert(Count <= 1);

					foreach (object o in this)
						return o;

					return null;
				}
			}

			public static bool operator <= (Set s1, Set s2)
			{
				foreach (object o in s1)
					if (!s2.Contains(o))
						return false;

				return true;
			}

			public static bool operator >= (Set s1, Set s2)
			{
				return s2 <= s1;
			}

			public static bool operator == (Set s1, Set s2)
			{
				if (isNull(s1) || isNull(s2))
					return isNull(s1) && isNull(s2);
				else
					return s1 <= s2 && s2 <= s1;
			}

			public static bool operator != (Set s1, Set s2)
			{
				return !(s1 == s2);
			}

			public static Set operator * (Set s1, Set s2)
			{
				Set r = new Set();

				foreach (object o in s1)
					if (s2.Contains(o))
						r.Add(o);

				return r;
			}

			public static Set operator + (Set s1, Set s2)
			{
				Set r = new Set();

				foreach (object o in s1)
					r.Add(o);

				foreach (object o in s2)
					r.Add(o);

				return r;
			}

			public static Set operator - (Set s1, Set s2)
			{
				Set r = new Set();

				foreach (object o in s1)
					if (!s2.Contains(o))
						r.Add(o);

				return r;
			}
		
			public override bool Equals (object o)
			{
				Set s = o as Set;

				return s != null && this == s;
			}

			public override int GetHashCode ()
			{
				int r = 0;

				foreach (object o in this)
					r ^= o.GetHashCode();

				return r;
			}

			public override string ToString ()
			{
				string r = "{\n";

				foreach (object o in this)
					r += string.Format("\t{0}\n", o);

				return r + "}\n";
			}
		}
	}
}