using Cryville.Common.Pdt;
using Cryville.Crtr.Components;
using Cryville.Crtr.Event;
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Profiling;

namespace Cryville.Crtr {
	public class SkinContainer {
		readonly PdtSkin skin;
		readonly Dictionary<SkinElement, Transform> matchedStatic
			= new Dictionary<SkinElement, Transform>();
		readonly Dictionary<SkinElement, Transform> matchedDynamic
			= new Dictionary<SkinElement, Transform>();
		public SkinContainer(PdtSkin _skin) {
			skin = _skin;
		}
		public void MatchStatic(ContainerState context) {
			matchedStatic.Clear();
			MatchStatic(skin, context, context.Handler.gogroup);

			foreach (var m in matchedStatic) {
				var el = m.Key;
				var obj = m.Value;
				foreach (var p in el.properties) {
					if (p.Key.Name == null)
						obj.gameObject.AddComponent(p.Key.Component);
					else {
						ChartPlayer.etor.ContextTransform = obj;
						ChartPlayer.etor.ContextEvent = context.Container;
						ChartPlayer.etor.Evaluate(GetPropOp(obj, p.Key), p.Value);
						ChartPlayer.etor.ContextEvent = null;
						ChartPlayer.etor.ContextTransform = null;
					}
				}
			}
		}
		void MatchStatic(SkinElement rel, ContainerState context, Transform anchor = null) {
			matchedStatic.Add(rel, anchor);
			foreach (var r in rel.elements) {
				var new_anchor = r.Key.MatchStatic(context, anchor);
				if (new_anchor != null) {
					MatchStatic(r.Value, context, new_anchor);
				}
			}
		}
		public void MatchDynamic(ContainerState context) {
			Profiler.BeginSample("SkinContainer.MatchDynamic");
			matchedDynamic.Clear();
			MatchDynamic(skin, context, context.Handler.gogroup);

			foreach (var m in matchedDynamic) {
				var el = m.Key;
				var obj = m.Value;
				foreach (var p in el.properties) {
					if (p.Key.Name == null) continue;
					if (p.Value.IsConstant) continue;
					ChartPlayer.etor.ContextTransform = obj;
					ChartPlayer.etor.ContextEvent = context.Container;
					ChartPlayer.etor.Evaluate(GetPropOp(obj, p.Key), p.Value);
					ChartPlayer.etor.ContextEvent = null;
					ChartPlayer.etor.ContextTransform = null;
				}
			}
			Profiler.EndSample();
		}
		void MatchDynamic(SkinElement rel, ContainerState context, Transform anchor = null) {
			matchedDynamic.Add(rel, anchor);
			foreach (var r in rel.elements) {
				Transform new_anchor;
				if (!matchedStatic.ContainsKey(r.Value)) continue;
				if (!r.Key.IsUpdatable(context)) continue;
				new_anchor = r.Key.MatchDynamic(
					context, r.Value, matchedStatic[r.Value], anchor
				);
				if (new_anchor != null) {
					MatchDynamic(r.Value, context, new_anchor);
				}
			}
		}
		PdtOperator GetPropOp(Transform obj, SkinPropertyKey key) {
			var ctype = key.Component;
			var comp = (SkinComponent)obj.GetComponent(ctype);
			if (comp == null) throw new InvalidOperationException("Component instance not found");
			PdtOperator result;
			if (!comp.PropOps.TryGetValue(key.Name, out result))
				throw new ArgumentException(string.Format("Property {0} not found on component", key.Name));
			return result;
		}
	}
}
