using Cryville.Common.Pdt;
using System;
using System.Collections.Generic;
using System.Linq;

namespace Cryville.Crtr {
	public class RulesetSelectors {
		readonly RulesetSelector[] selectors;
		public RulesetSelectors(IEnumerable<RulesetSelector> s) {
			selectors = s.ToArray();
		}
		public void Optimize(PdtEvaluatorBase etor) {
			for (int i = 0; i < selectors.Length; i++) {
				selectors[i].Optimize(etor);
			}
		}
		public IEnumerable<ChartEvent> Match(ChartEvent ev) {
			IEnumerable<ChartEvent> result = new ChartEvent[] { ev };
			foreach (var sel in selectors) {
				IEnumerable<ChartEvent> temp = new ChartEvent[0];
				foreach (var e in result) {
					var m = sel.Match(e);
					if (m != null) temp = temp.Concat(m);
				}
				result = temp;
			}
			return result;
		}
		public override string ToString() {
			if (selectors.Length == 0) return "";
			bool flag = false;
			string r = "";
			foreach (var s in selectors) {
				if (flag) r += " " + s.ToString();
				else { r += s.ToString(); flag = true; }
			}
			return r;
		}
	}

	public abstract class RulesetSelector {
		public virtual void Optimize(PdtEvaluatorBase etor) { }
		public abstract IEnumerable<ChartEvent> Match(ChartEvent ev);
		public class CreateItem : RulesetSelector {
			public override string ToString() {
				return "$";
			}
			public override IEnumerable<ChartEvent> Match(ChartEvent ev) {
				if (!(ev is EventList)) throw new ArgumentException("Event is not event list");
				var tev = (EventList)ev;
				var result = tev.Create();
				tev.Events.Add(result); // TODO create at
				return new ChartEvent[] { result };
			}
		}
		public class EventType : RulesetSelector {
			readonly string _type;
			public EventType(string type) { _type = type; }
			public override string ToString() {
				return _type;
			}
			public override IEnumerable<ChartEvent> Match(ChartEvent ev) {
				if (!(ev is EventContainer)) throw new ArgumentException("Event is not container");
				var tev = (EventContainer)ev;
				return new ChartEvent[] { tev.GetEventsOfType(_type) };
			}
		}
		public class Index : RulesetSelector {
			public override string ToString() {
				return "#";
			}
			public override IEnumerable<ChartEvent> Match(ChartEvent ev) {
				if (!(ev is EventList)) throw new ArgumentException("Event is not event list");
				var tev = (EventList)ev;
				return tev.Events; // TODO select at
			}
		}
		public class Property : RulesetSelector {
			readonly PdtExpression _exp;
			readonly PdtOperator _op;
			bool _flag;
			public Property(PdtExpression exp) {
				_exp = exp;
				_op = new PropOp.Boolean(v => _flag = v);
			}
			public override string ToString() {
				return string.Format("> {{{0}}}", _exp);
			}
			public override void Optimize(PdtEvaluatorBase etor) {
				etor.Optimize(_exp);
			}
			public override IEnumerable<ChartEvent> Match(ChartEvent ev) {
				ChartPlayer.etor.ContextEvent = ev;
				ChartPlayer.etor.Evaluate(_op, _exp);
				ChartPlayer.etor.ContextEvent = null;
				if (_flag) return new ChartEvent[] { ev };
				else return null;
			}
		}
	}
}
