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

using glue.Extensions.String;
using glue.Extensions.Enumerable;
using agree;
using agree.Parse;
using glue.Tokenization;
using glue.Collections.XSpinLock;

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
/// 
/// </summary>
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public struct TestEdge : TestChart.IMotherDaughter, IEquatable<TestEdge>
{
	static TestEdge[] rgte_empty = new TestEdge[0];

	public TestEdge(TestGrammarRule tgr, String s)
	{
		this.tgr = tgr;
		this.s = s;
	}
	public String s;
	public TestGrammarRule tgr;

	public override string ToString()
	{
		return String.Format("{0}", s);
	}

	public IEnumerable<TestEdge> RuleDaughters()
	{
		return (tgr != null) ? tgr.RuleDaughters() : rgte_empty;
	}

	public TestEdge Self
	{
		get { return this; }
	}

	public void Dispose()
	{
	}

	public bool Equals(TestEdge other)
	{
		return s == other.s;
	}


	public bool SpinCompare(TestEdge other)
	{
		throw new NotImplementedException();
	}
};


public interface ICountAddCollection<T> : IEnumerable<T>
{
	int Count { get; }
	void Add(T t);
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
/// 
/// </summary>
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
[DebuggerDisplay("{ToString(),nq}")]
public class TestGrammarRule : ICountAddCollection<TestEdge>, TestChart.IGrammarRule
{
	TestEdge exp;
	public TestGrammarRule(String p, int i_key_dtr, params String[] _dx)
	{
		this.exp = new TestEdge(this, p);
		this.i_key_dtr = i_key_dtr;
		this.daughters = _dx.Select(s => new TestEdge(this, s)).ToArray();
	}

	public int i_key_dtr;
	TestEdge[] daughters;

	public TestEdge Self { get { return exp; } }

	public IList<TestEdge> RuleDaughters() { return daughters; }

	IEnumerable<TestEdge> TestChart.IMotherDaughter.RuleDaughters() { throw new NotImplementedException(); }

	// FOR C# INITIALIZATION SYNTAX ONLY
	public void Add(TestEdge t) { daughters = daughters.AsEnumerable<TestEdge>().Append(t).ToArray(); }
	public int Count { get { return daughters.Length; } }
	public IEnumerator<TestEdge> GetEnumerator() { return (IEnumerator<TestEdge>)daughters.GetEnumerator(); }
	System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return GetEnumerator(); }

	public override string ToString()
	{
		return String.Format("{1} -> {0}", Self, daughters.Select(d => d.ToString()).StringJoin(" "));
	}

	public void Dispose()
	{
	}

	public int KeyDaughterIndex
	{
		get { return 0; }
	}


	public bool SpinCompare(TestEdge other)
	{
		throw new NotImplementedException();
	}
};

public class TestLexicalAnalysis : TestChart.IParseChartEdge
{
	public Span cs;
	public TestEdge lex;

	public Span ChartSpan
	{
		get { return cs; }
	}

	public TestEdge Self
	{
		get { return lex; }
	}

	public bool SpinCompare(TestEdge other)
	{
		throw new NotImplementedException();
	}

	public string Text
	{
		get { throw new NotImplementedException(); }
	}


	public void Dispose()
	{
	}

	Span ChartBase<TestEdge>.IParseChartEdge.ChartSpan
	{
		get { throw new NotImplementedException(); }
	}


	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <summary>
	/// IAtomicallySequencable(ParseChart.IParseChartToken) implementation
	/// </summary>
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////

	int i_seq = unchecked((int)uint.MaxValue);		// fix fix

	public uint SequenceId
	{
		get { return (uint)i_seq; }
	}

	public void StampSequence(AtomicSequencer ast)
	{
		ast.StampLocation(ref i_seq);
	}

	public bool SetInert(AtomicSequencer ast)
	{
		return ast.SetInert(ref i_seq);
	}

	public bool IsInert(AtomicSequencer ast)
	{
		return (uint)i_seq == ast.InertValue;
	}
};

public class TestLexicalEntry
{
	String[] words;
	TestEdge fs;

	public TestLexicalEntry(String word, TestEdge fs)
	{
		this.words = new String[1] { word };
		this.fs = fs;
	}
	public IList<string> Lemmata
	{
		get { return words; }
	}

	public TestEdge Self
	{
		get { return fs; }
	}


	public bool SpinCompare(TestEdge other)
	{
		throw new NotImplementedException();
	}
}

partial class Program
{
	static public Random rnd = new Random();

	static void Main(string[] args)
	{
		new Program().ProgramMain(args);
	}

	static TestGrammarRule[] rules1 = new TestGrammarRule[]
	{
		new TestGrammarRule("S", -1, "NP", "VP"),
		new TestGrammarRule("NP", -1, "DET", "N"),
		new TestGrammarRule("VP", 0, "VT", "NP"),
        new TestGrammarRule("VP", -1, "VI"),
		new TestGrammarRule("NP", -1, "N"),
		new TestGrammarRule("NP-C-MID", -1, "NP","CONJ"),
		new TestGrammarRule("NP-CONJ", -1,"NP-C-MID","NP"),
		new TestGrammarRule("NP-CONJ", 1,"NP","NP-CONJ"),
		new TestGrammarRule("NP", -1,"NP-CONJ"),
		new TestGrammarRule("NP", -1,"NP","PP"),
		new TestGrammarRule("VP", 1,"VP","PP"),
		new TestGrammarRule("PP", -1,"P","NP"),
	};

	static TestGrammarRule[] rules2 = new TestGrammarRule[]
	{
		new TestGrammarRule("S", -1,"NP","VP"),
		new TestGrammarRule("NP", -1,"DET","N"),
		new TestGrammarRule("VP", 0,"VT","NP"),
        new TestGrammarRule("VP", -1,"VI"),
		new TestGrammarRule("NP", -1,"N"),
		new TestGrammarRule("NP-CONJ", -1,"NP","CONJ","NP"),
		new TestGrammarRule("NP-CONJ", 1,"NP","NP-CONJ"),
		new TestGrammarRule("NP", -1,"NP-CONJ"),
		new TestGrammarRule("NP", -1,"NP","PP"),
		new TestGrammarRule("VP", 1,"VP","PP"),
		new TestGrammarRule("PP", -1,"P","NP"),
	};

	static TestGrammarRule[] rules3 = new TestGrammarRule[]
	{
		new TestGrammarRule("S", -1,"NP","VP"),
		new TestGrammarRule("NP", -1,"DET","N"),
		new TestGrammarRule("VP", 0,"VT","NP"),
        new TestGrammarRule("VP", -1,"VI"),
		new TestGrammarRule("NP", -1,"N"),
		new TestGrammarRule("S", -1,"VP"),
	};

	public static TestEdge[] start_sym = new TestEdge[] { new TestEdge(null, "S") };

	static Dictionary<String, String[]> lex = new Dictionary<string, String[]>
	{
		{ "i", new String[] { "N"} },
		{ "saw", new String[] { "N","VT"} },
		{ "that", new String[] { "DET","N"} },
		{ "man", new String[] { "N","VT","EXCL"} },
		{ "the", new String[] { "DET"} },
		{ "hatch", new String[] { "N", "VI"} },
		{ "and", new String[] { "CONJ"} },
		{ "pump", new String[] { "N","VI","VT"} },
		{ "with", new String[] { "P"} },
		{ "telescope", new String[] { "N"} },
	};

	public class TestItem
	{
		public TestItem(TestGrammarRule[] r, String input, int h)
		{
			this.rules = r;
			this.input = input;
			this.hash = h;
		}
		public TestGrammarRule[] rules;
		public String input;
		public int hash;
		public String[] warr;
	};

	static TestItem[] tests = new TestItem[]
	{
		new TestItem(rules1, "I saw that man the hatch and pump with the telescope", 0xF1A75),//0xF19F1),
		new TestItem(rules2, "I saw that man the hatch and pump with the telescope", 0xE84D5),//0xF0ADD),
		new TestItem(rules3, "hatch", 0x07DFC),
	};
};