using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Mesen.GUI.Config;
using Mesen.GUI.Forms;

namespace Mesen.GUI
{
	public class CursorManager
	{
		private static bool _cursorHidden = false;
		private static Point _lastPosition;
		private static Timer _tmrHideMouse = new Timer();
		private static Timer _tmrCheckMouseMove = new Timer();
		private static bool _mouseCaptured = false;

		static CursorManager()
		{
			_tmrHideMouse.Interval = 3000;
			_tmrHideMouse.Tick += tmrHideMouse_Tick;
			_tmrCheckMouseMove.Interval = 500;
			_tmrCheckMouseMove.Tick += tmrCheckMouseMove_Tick;
			_tmrCheckMouseMove.Start();
		}

		public static void StopTimers()
		{
			_tmrCheckMouseMove.Stop();
			_tmrHideMouse.Stop();
		}

		private static void tmrCheckMouseMove_Tick(object sender, EventArgs e)
		{
			//Rarely the cursor becomes hidden despite leaving the window or moving
			//Have not been able to find a reliable way to reproduce it yet
			//This is a patch to prevent that bug from having any negative impact
			if(!_mouseCaptured && _lastPosition != Cursor.Position) {
				_lastPosition = Cursor.Position;

				bool running = InteropEmu.IsRunning() && !InteropEmu.IsPaused();
				if(running && ConfigManager.Config.InputInfo.HideMousePointerForZapper && CursorManager.IsLightGun) {
					//Keep mouse hidden when using zapper if option to hide mouse is enabled
					return;
				}

				ShowMouse();
			}
		}

		private static void tmrHideMouse_Tick(object sender, EventArgs e)
		{
			if(InteropEmu.IsRunning() && !InteropEmu.IsPaused()) {
				HideMouse();
				_tmrHideMouse.Stop();
			} else {
				ShowMouse();
				_tmrHideMouse.Stop();
			}
		}

		private static void ShowMouse()
		{
			if(_cursorHidden) {
				Cursor.Show();
				_cursorHidden = false;
			}
		}

		private static void HideMouse()
		{
			if(!_cursorHidden) {
				Cursor.Hide();
				_cursorHidden = true;
			}
		}

		private static bool IsLightGun
		{
			get { return InteropEmu.HasZapper() || (InteropEmu.GetConsoleType() == ConsoleType.Famicom && InteropEmu.GetExpansionDevice() == InteropEmu.ExpansionPortDevice.BandaiHyperShot); }
		}

		public static bool NeedMouseIcon
		{
			get { return CursorManager.IsLightGun || (InteropEmu.GetConsoleType() == ConsoleType.Famicom && InteropEmu.GetExpansionDevice() == InteropEmu.ExpansionPortDevice.OekaKidsTablet); }
		}

		public static void OnMouseMove(Control ctrl)
		{
			if(_mouseCaptured && AllowMouseCapture) {
				HideMouse();
				_tmrHideMouse.Stop();
				Form frm = Application.OpenForms[0];
				Point centerPos = frm.PointToScreen(new Point(frm.Width / 2, frm.Height / 2));
				Point diff = new Point(Cursor.Position.X - centerPos.X, Cursor.Position.Y - centerPos.Y);
				if(diff.X != 0 || diff.Y != 0) {
					InteropEmu.SetMouseMovement((Int16)diff.X, (Int16)diff.Y);
					Cursor.Position = centerPos;
				}
			} else {
				_mouseCaptured = false;

				if(!InteropEmu.IsRunning() || InteropEmu.IsPaused()) {
					ShowMouse();
				} else if(ConfigManager.Config.InputInfo.HideMousePointerForZapper && CursorManager.IsLightGun) {
					//Keep mouse hidden when using zapper if option to hide mouse is enabled
					HideMouse();
					return;
				}

				_tmrHideMouse.Stop();

				if(!CursorManager.NeedMouseIcon) {
					//Only hide mouse if no zapper (otherwise this could be pretty annoying)
					ctrl.Cursor = Cursors.Default;

					if(InteropEmu.IsRunning() && !InteropEmu.IsPaused()) {
						_tmrHideMouse.Start();
					}
				}
			}
		}

		public static void OnMouseLeave()
		{
			_tmrHideMouse.Stop();
			ShowMouse();
		}

		public static bool AllowMouseCapture
		{
			get
			{
				if(!InteropEmu.IsRunning()) {
					return false;
				}

				if(InteropEmu.IsPaused()) {
					return false;
				}

				if(InteropEmu.CheckFlag(EmulationFlags.InBackground)) {
					return false;
				}

				if(InteropEmu.GetConsoleType() == ConsoleType.Famicom) {
					switch(InteropEmu.GetExpansionDevice()) {
						case InteropEmu.ExpansionPortDevice.ArkanoidController:
						case InteropEmu.ExpansionPortDevice.HoriTrack:
							return true;
					}
				}

				for(int i = 0; i < 4; i++) {
					switch(InteropEmu.GetControllerType(i)) {
						case InteropEmu.ControllerType.ArkanoidController:
						case InteropEmu.ControllerType.SnesMouse:
						case InteropEmu.ControllerType.SuborMouse:
							return true;
					}
				}
				return false;
			}
		}

		public static void ReleaseMouse()
		{
			_mouseCaptured = false;
			ShowMouse();
		}

		public static void CaptureMouse()
		{
			if(AllowMouseCapture) {
				if(!_mouseCaptured) {
					InteropEmu.DisplayMessage("Input", ResourceHelper.GetMessage("MouseModeEnabled"));
				}
				_mouseCaptured = true;
				HideMouse();
				Form frm = Application.OpenForms[0];
				Point centerPos = frm.PointToScreen(new Point(frm.Width / 2, frm.Height / 2));
				Cursor.Position = centerPos;
			}
		}
	}
}