using System;
using UnityEngine;
using unity = UnityEngine;

namespace Cryville.Common.Unity.Input {
	public class UnityTouchHandler : InputHandler {
		GameObject receiver;

		public UnityTouchHandler() {
			if (!unity::Input.touchSupported) {
				throw new NotSupportedException("Unity touch is not supported on this device");
			}
		}

		protected override void ActivateImpl() {
			receiver = new GameObject("__touchrecv__");
			receiver.AddComponent<UnityPointerReceiver>().SetHandler(this);
		}

		protected override void DeactivateImpl() {
			if (receiver) GameObject.Destroy(receiver);
		}

		public override void Dispose(bool disposing) {
			if (disposing) {
				DeactivateImpl();
			}
		}

		public override bool IsNullable(int type) {
			if (type != 0) throw new ArgumentOutOfRangeException(nameof(type));
			return true;
		}

		public override byte GetDimension(int type) {
			if (type != 0) throw new ArgumentOutOfRangeException(nameof(type));
			return 2;
		}

		public override string GetTypeName(int type) {
			switch (type) {
				case 0: return "Touch";
				default: throw new ArgumentOutOfRangeException(nameof(type));
			}
		}

		public override double GetCurrentTimestamp() {
			return Time.realtimeSinceStartupAsDouble;
		}

		public class UnityPointerReceiver : MonoBehaviour {
			UnityTouchHandler handler;
			public void SetHandler(UnityTouchHandler h) {
				handler = h;
			}
			void Update() {
				double time = Time.realtimeSinceStartupAsDouble;
				for (int i = 0; i < unity::Input.touchCount; i++) {
					var t = unity::Input.GetTouch(i);
					Vector2 pos = UnityCameraUtils.ScreenToWorldPoint(t.position);
					var vec = new InputVector(time, pos);
					if (t.phase == TouchPhase.Began || t.phase == TouchPhase.Stationary || t.phase == TouchPhase.Moved) {
						handler.Feed(0, t.fingerId, vec);
					}
					else if (t.phase == TouchPhase.Ended || t.phase == TouchPhase.Canceled) {
						handler.Feed(0, t.fingerId, vec);
						handler.Feed(0, t.fingerId, new InputVector(time));
					}
				}
			}
		}
	}
}
