using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;

using miew.Enumerable;
using miew.String;
using miew.Tokenization;

namespace agree
{
	public partial class LexicalAnalysis : IEnumerable<IParseObj>
	{
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// 
		/// </summary>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		[DebuggerDisplay("{ToString(),nq}")]
		public abstract class LexicalTransform
		{
			public LexicalTransform(IList<String> form, Entry license)
			{
				this.form = form;
				this.license = license;
			}

			public LexicalTransform(String s_form, Entry license)
				: this(new String[] { s_form }, license)
			{
			}

			public LexicalTransform(IList<String> form, Entry license, Tfs feature_structure)
				: this(form, license)
			{
				this.feature_structure = feature_structure;
			}

			public LexicalTransform(String s_form, Entry license, Tfs feature_structure)
				: this(new String[] { s_form }, license, feature_structure)
			{
			}

			[DebuggerBrowsable(DebuggerBrowsableState.Never)]
			readonly IList<String> form;

			readonly public Entry license;

			public bool f_licensed;

			public Tfs feature_structure;

			public IList<String> CurrentForm { get { return form; } }

			public override string ToString()
			{
				return String.Format("{0} {1}", form.Select(s => s.Quotes()).StringJoin(" "), license.Name);
			}
		};

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// Lexical transformations which are licensed by lexical rules
		/// </summary>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		public abstract class LxRule : LexicalTransform
		{
			public LxRule(IList<String> form, LexicalRule license)
				: base(form, license)
			{
			}
			public LxRule(IList<String> form, LexicalRule license, Tfs feature_structure)
				: base(form, license, feature_structure)
			{
			}
			public LxRule(String s_form, LexicalRule license)
				: base(s_form, license)
			{
			}
			public LxRule(String s_form, LexicalRule license, Tfs feature_structure)
				: base(s_form, license, feature_structure)
			{
			}

			public LexicalRule LexicalRule { get { return (LexicalRule)license; } }
		};

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// 
		/// </summary>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		public class LxNonAffixing : LxRule
		{
			public LxNonAffixing(IList<String> form, LexicalRule license, Tfs feature_structure)
				: base(form, license, feature_structure)
			{
			}
		};

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// (abstract)
		/// </summary>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		abstract public class LxAffixing : LxRule
		{
			public LxAffixing(String s_form, LexicalRule license)
				: base(s_form, license)
			{
			}
			public LxAffixing(String s_form, LexicalRule license, Tfs feature_structure)
				: base(s_form, license, feature_structure)
			{
			}
		}

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// 
		/// </summary>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		public class LxRegularAffixing : LxAffixing
		{
			public LxRegularAffixing(String s_form, LexicalRule license)
				: base(s_form, license)
			{
			}
			public LxRegularAffixing(String s_form, LexicalRule license, Tfs feature_structure)
				: base(s_form, license, feature_structure)
			{
			}
		};

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// 
		/// </summary>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		public class LxIrregular : LxAffixing
		{
			public LxIrregular(String s_form, LexicalRule license)
				: base(s_form, license)
			{
			}
			public LxIrregular(String s_form, LexicalRule license, Tfs feature_structure)
				: base(s_form, license , feature_structure)
			{
			}
		};

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// (abstract)
		/// the lifetime of a lexical stem FS is managed by the lexicon, so derived classes should not release them
		/// </summary>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		public abstract class LxStem : LexicalTransform
		{
			public LxStem(IList<String> form, LexicalEntry le)
				: base(form, le, le.GetExpanded())
			{
			}

			public LexicalEntry LexicalEntry { get { return (LexicalEntry)license; } }

			public abstract Span ChartSpan { get; }
		};

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// 
		/// </summary>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		public class LxSingleTokenStem : LxStem
		{
			TokenSpanToken tok;

			public LxSingleTokenStem(TokenSpanToken tok, LexicalEntry le)
				: base(new String[] { le.Lemmata[0] }, le)
			{
				this.tok = tok;
			}

			public override Span ChartSpan
			{
				get { return tok.TokenSpan; }
			}
		};

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// 
		/// </summary>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		public class LxMultiTokenStem : LxStem
		{
			Span sp;

			public LxMultiTokenStem(Span sp, LexicalEntry le)
				: base(le.Lemmata, le)
			{
				this.sp = sp;
			}

			public override Span ChartSpan
			{
				get { return sp; }
			}
		};
	};
}