/*
 * Bernoulli Compiler
 * Copyright (c) Cornell University
 * Department of Computer Science
 * 
 * Kamen Yotov (kamen@yotov.org)
 * 
 * $Source: C:/CVS/kyotov/kyotov/Research/BC/Core/Grammars/Sequence.cs,v $
 * $Revision: 1.10 $
 * $Date: 2002/12/05 03:07:54 $
 */

using System;
using System.Collections;

namespace BC.Core
{
	namespace Grammars
	{
		using Symbols;
		using Reductions;

		[Serializable]
		public class Sequence: ArrayList, IEnumerable, ICloneable
		{
			public new Symbol this [int i]
			{
				get
				{
					return i < Count ? (Symbol)base[i] : null;
				}
			}

			public Symbol Last
			{
				get
				{
					return this[Count - 1];
				}
			}

			public Sequence ()
			{
			}

			public Sequence (Symbol s)
			{
				Add(s);
			}

			public Sequence (ICollection c)
			{
				AddRange(c);
			}

			public new Sequence GetRange (int f, int c)
			{
				Sequence r = new Sequence();

				r.AddRange(base.GetRange(f, c));

				return r;
			}

			public Sequence Left (int c)
			{
				return GetRange(0, c);
			}

			public Sequence Tail (int c)
			{
				return GetRange(c, Count - c);
			}

			public Sequence Right (int c)
			{
				return GetRange(Count - c, c);
			}

			public void Append (Sequence a)
			{
				AddRange(a);
			}

			public override bool Equals (object o)
			{
				Sequence a = o as Sequence;

				if (a != null && Count == a.Count)
				{
					for (int i = 0; i < Count; i++)
						if (!this[i].Equals(a[i]))
							return false;

					return true;
				}

				return false;
			}

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

				foreach (Symbol s in this)
					r ^= s.GetHashCode();

				return r;
			}

			public static bool Match (Sequence s, Sequence p)
			{
				if (s.Count != p.Count)
					return false;

				for (int i = 0; i < s.Count; i++)
					if (!Symbol.Match(s[i], p[i]))
						return false;

				return true;
			}

			public static Sequence operator + (Sequence a, string s)
			{
				return a + new Terminal(s);
			}

			public static Sequence operator + (Sequence a, Symbol s)
			{
				Sequence n = new Sequence();

				n.AddRange(a);
				n.Add(s);

				return n;
			}

			public static Sequence operator + (Sequence a1, Sequence a2)
			{
				Sequence a = new Sequence();

				a.AddRange(a1);
				a.AddRange(a2);

				return a;
			}

			public static Alternative operator + (Sequence a, Reduction r)
			{
				Alternative x = new Alternative(a);

				x.Reduction += r;

				return x;
			}

			public static Alternatives operator | (Sequence a1, Sequence a2)
			{
				return (Alternative)a1 | (Alternative)a2;
			}

			public static implicit operator Alternative (Sequence s)
			{
				return new Alternative(s);
			}

			public static implicit operator Alternatives (Sequence s)
			{
				return (Alternative)(s);
			}

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

				if (Count > 0)
					foreach (Symbol s in this)
						r += string.Format(" {0:\"}", s);
				else
					r += new Epsilon();

				return r;
			}

			new public object Clone ()
			{
				Sequence s = new Sequence();

				foreach (Symbol x in this)
				{
					Symbol ns = (Symbol)x.Clone();

					ns.Result = Global.Clone(ns.Result);

					s.Add(ns);
				}

				return s;
			}

			public int DeepCount
			{
				get
				{
					int r = 0;

					foreach (Symbol x in this)
					{
						if (x is VirtualSymbol)
							r += ((VirtualSymbol)x).Sequence.DeepCount;
						else
							r++;
					}

					return r;
				}
			}
		}
	}
}