using System.Collections;
using System.Collections.Generic;
using System;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;

public class main : MonoBehaviour
{
	protected bool EventLock = false;
    protected Animrig.Unity.AnimationrigStateComponent anim;
	protected Dropdown AnimationCombo0;
	protected Dropdown AnimationCombo1;
	protected Dropdown PresetCombo;
	protected Dropdown DirectInputCombo;
	protected GameObject DirectInputPanel;
	protected GameObject DirectInputCursor;
	protected Text ValueText;
	protected Text SpineTracksText;

	// Start is called before the first frame update
	void Start()
    {
        // get AnimationrigState component
        {
            var o = GameObject.Find("AnimationrigState");
            anim = o.GetComponent<Animrig.Unity.AnimationrigStateComponent>();
        }
        // setup track animation dropdown
        {
			EventLock = true;
			{
				var o = GameObject.Find("AnimationDropdown0");
				AnimationCombo0 = o.GetComponent<Dropdown>();
				AnimationCombo0.onValueChanged.AddListener(OnAnimation0Change);
				AnimationCombo0.ClearOptions();

				var opt = new Dropdown.OptionData("empty");
				AnimationCombo0.options.Add(opt);
				AnimationCombo0.value = 0;
				AnimationCombo0.RefreshShownValue();   // need call refresh. :Q
			}
			{
				var o = GameObject.Find("AnimationDropdown1");
				AnimationCombo1 = o.GetComponent<Dropdown>();
				AnimationCombo1.onValueChanged.AddListener(OnAnimation1Change);
				AnimationCombo1.ClearOptions();

				var opt = new Dropdown.OptionData("empty");
				AnimationCombo1.options.Add(opt);
				AnimationCombo1.value = 0;
				AnimationCombo1.RefreshShownValue();   // need call refresh. :Q
			}

			foreach (var a in anim.Data.Animations)
            {
				if (a.Name == "setup") continue;

                var opt = new Dropdown.OptionData(a.Name);
				AnimationCombo0.options.Add(opt);
				AnimationCombo1.options.Add(opt);
			}
			EventLock = false;
		}

		// setup preset dropdown
		{
			EventLock = true;
			{
				var o = GameObject.Find("PresetDropdown");
				PresetCombo = o.GetComponent<Dropdown>();
				PresetCombo.onValueChanged.AddListener(OnPresetChange);
				PresetCombo.ClearOptions();

				var opt = new Dropdown.OptionData("default");
				PresetCombo.options.Add(opt);
				PresetCombo.value = 0;
				PresetCombo.RefreshShownValue();   // need call refresh. :Q
			}
			foreach(var p in anim.Preset.list)
			{
				var opt = new Dropdown.OptionData(p.Key);
				PresetCombo.options.Add(opt);
			}

			EventLock = false;
		}

		// setup direct input dropdown
		{
			EventLock = true;
			{
				var o = GameObject.Find("DirectInputDropdown");
				DirectInputCombo = o.GetComponent<Dropdown>();
				DirectInputCombo.onValueChanged.AddListener(OnDirectInputIndexChange);
				DirectInputCombo.ClearOptions();
			}
			var input = anim.State.Inputs[0];
			for (var i = 0; i < input.ValueCount / 2; i++)
			{
				var opt = new Dropdown.OptionData($"{i} : {input.ValueNames[i*2]}");
				DirectInputCombo.options.Add(opt);
			}
			DirectInputCombo.value = 0;
			DirectInputCombo.RefreshShownValue();	// need call refresh. :Q

			EventLock = false;

			DirectInputPanel = GameObject.Find("DirectInputPanel");
			DirectInputCursor = GameObject.Find("DirectInputCursor");
		}

		// value text
		{
			var o = GameObject.Find("ValueLabel");
			ValueText = o.GetComponent<Text>();
		}
		// SpineTracks text
		{
			var o = GameObject.Find("SpineTracksLabel");
			SpineTracksText = o.GetComponent<Text>();
		}

        // setup default animation
        anim.State.EntryTrack(0, "setup");
		// event
		anim.State.OnEvent = OnAnimationrigEvent;
	}

    // Update is called once per frame
    void Update()
    {
		UpdateDirectInputPanel();
		UpdateSpineTracksText();
	}

	// update direct input panel
	protected void UpdateDirectInputPanel()
	{
		// panel size
		var rt = DirectInputPanel.transform as RectTransform;
		var w = rt.rect.width;
		var h = rt.rect.height;

		// select input value
		var no = DirectInputCombo.value;
		var input = anim.State.Inputs[0];
		if (no < -1) no = 0;
		if (no >= input.ValueCount / 2) no = 0;
		var a1 = input.Values[no * 2 + 0].Value;
		var a2 = input.Values[no * 2 + 1].Value;

		// set
		{
			a1 = Math.Min(Math.Max(a1, -1.0f), 1.0f);
			a2 = Math.Min(Math.Max(a2, -1.0f), 1.0f);
			var x = (float)((w * 0.5) * a1);
			var y = (float)((h * 0.5) * a2);
			x = x + (w * 0.5f);
			y = y + (h * 0.5f);

			var rt2 = DirectInputCursor.transform as RectTransform;
			y = y - rt.rect.height;
			rt2.localPosition = new UnityEngine.Vector3(x, y, 0.0f);
		}

		// text
		{
			var s = "x : " + a1.ToString("f2");
			s = s + "\r\n" + "y : " + a2.ToString("f2");
			ValueText.text = s;
		}
	}
	protected void UpdateSpineTracksText()
	{
        string inMixBlendToString(Spine.MixBlend m)
        {
            switch (m)
            {
                case Spine.MixBlend.Add:
                    return "add";
                case Spine.MixBlend.Replace:
                    return "rep";
                case Spine.MixBlend.Setup:
                    return "setup";
                case Spine.MixBlend.First:
                    return "first";
            }
            return "";
        }
		var s = "";

		{
			var o = anim.RendererObjects[0];
			if (o == null) return;
			var c = o.GetComponent<Spine.Unity.SkeletonAnimation>();
			if (c == null) return;

			var index = 0;
			foreach(var t in c.state.Tracks)
			{
				if (t == null)
				{
					s += $"<color=#888888ff>no.{index} : null</color>" + "\r\n";
				}
				else
				{
					var name = "empty";
					if (t.Animation != null) name = t.Animation.Name;
					var color = "<color=#ffffffff>";
					if (t.Alpha < 0.001) color = "<color=#888888ff>";
					// var time = t.TrackTime.ToString("f1");
					var alpha = (t.Alpha*100).ToString("f2");
					s += $"{color}track.{index} : {inMixBlendToString(t.MixBlend)} {alpha}% : {name}</color>\r\n";
				}
				index++;
			}
		}

		SpineTracksText.text = s;
	}

	// event
	public void OnAnimation0Change(int value)
	{
		if (EventLock) return;
		if (value < 0) return;
		var name = AnimationCombo0.options[value].text;
		if (name == "empty")
		{
			anim.State.ClearTrackFade(2, 1.0f);
		}
		else
		{
			anim.State.EntryTrackFade(2, name, 1.0f);
		}
	}
	public void OnAnimation1Change(int value)
	{
		if (EventLock) return;
		if (value < 0) return;
		var name = AnimationCombo1.options[value].text;
		if (name == "empty")
		{
			anim.State.ClearTrackFade(3, 1.0f);
		}
		else
		{
			anim.State.EntryTrackFade(3, name, 1.0f);
		}
	}
	public void OnPresetChange(int value)
	{
		if (EventLock) return;
		if (value < 0) return;
		var name = PresetCombo.options[value].text;
		if (name == "default")
		{
			anim.Preset.SetDefault(anim.State.Inputs[0], 1.0f);
		}
		else
		{
			anim.Preset.SetPreset(anim.State.Inputs[0], name, 1.0f);
		}
	}
	public void OnAnimationrigEvent(Animrig.AnimationrigState state, ref Animrig.StateEventData data)
	{
		// If you want to know the event source object, use InputObject.UserObject property.
		// anim.State.Inputs[0].UserObject = YoureGameObject;			// set
		// var YoureGameObject = data.Input.UserObject as GameObject;	// get
		if (data.Strings0 != "") Debug.Log(data.Strings0);
		if (data.Strings1 != "") Debug.Log(data.Strings1);
	}
	public void OnDirectInputIndexChange(int value)
	{
		//
	}
	public void OnDirectInputPanelDrag(BaseEventData eventData)
	{
		var ev = eventData as PointerEventData;
		float x, y;
		{
			var rt = DirectInputPanel.transform as RectTransform;
			var v = rt.InverseTransformPoint(new Vector3(ev.position.x, ev.position.y, 0));
			x = v.x;
			y = rt.rect.height + v.y;
		}

		float a1, a2;
		{
			// panel size
			var rt = DirectInputPanel.transform as RectTransform;
			var w = rt.rect.width;
			var h = rt.rect.height;

			a1 = (float)(x - w * 0.5f);
			a2 = (float)(y - h * 0.5f);
			a1 = a1 / (w * 0.5f);
			a2 = a2 / (h * 0.5f);
			a1 = Math.Min(Math.Max(a1, -1.0f), 1.0f);
			a2 = Math.Min(Math.Max(a2, -1.0f), 1.0f);
		}
		{
			// select input value
			var no = DirectInputCombo.value;
			var input = anim.State.Inputs[0];
			if (no < -1) no = 0;
			if (no >= input.ValueCount / 2) no = 0;

			anim.State.Inputs[0].SetValue(no * 2 + 0, a1, 0.0f);
			anim.State.Inputs[0].SetValue(no * 2 + 1, a2, 0.0f);
		}

	}
}
