using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

using miew.Debugging;
using miew.Enumerable;
using miew.Tokenization;

namespace agree
{
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <summary>
	/// 
	/// </summary>
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public sealed class Submitter
	{
		readonly Grammar g;
		ITokenizer tokenizer;

		public Submitter(Config config, Grammar g)
		{
			this.g = g;
			this.tokenizer = null;

			ConfigureTokenizer(g.lex);
			config.parser.PropertyChanged += new PropertyChangedEventHandler(OnParserConfigChanged);
		}

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// 
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////		

		public ITokenizer Tokenizer
		{
			get { return tokenizer; }
			set { tokenizer = value; }
		}

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// </summary>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		public Task<ParseControl> Parse(String s)
		{
			return Parse(new TokenizedString(s, tokenizer));
		}

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// In order to use the 'attached to child task' functionality, we start a root task to wrap all parse tasks
		/// </summary>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		public Task<ParseControl> Parse(TokenSet tok_set)
		{
			return new ParseControl(g).Parse(tok_set);
		}

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// 
		/// </summary>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		void OnParserConfigChanged(object sender, PropertyChangedEventArgs e)
		{
			switch (e.PropertyName)
			{
				case "TokenizerType":
					ConfigureTokenizer(g.lex);
					break;
			}
		}

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// 
		/// </summary>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		void ConfigureTokenizer(Lexicon lex)
		{
			System.Type T_tok = this.g.config.parser.TokenizerType;

			ConstructorInfo ci;
			if (T_tok == null)
			{
				tokenizer = new SpaceCharTokenizer();
			}
			else if (T_tok.GetConstructor(new System.Type[0]) != null)
			{
				tokenizer = (ITokenizer)Activator.CreateInstance(T_tok);
			}
			else if ((ci = T_tok.GetConstructor(new System.Type[] { typeof(Func<String, bool>) })) != null)
			{
				Func<String, bool> af = w => lex[w].Any(q => q.Lemmata.Count == 1);
				tokenizer = (ITokenizer)ci.Invoke(new Object[] { af });
			}
			else
			{
				throw new Exception(String.Format("Could not determine how to construct the tokenizer '{0}'", T_tok.Name));
			}
		}
	};
}