using System;
using System.Runtime.InteropServices;
using System.Text;

namespace Cryville.Common.Unity.Input {
	static class NativeMethods {
		[StructLayout(LayoutKind.Sequential)]
		public struct MONITORINFO {
			public int cbSize;
			public RECT rcMonitor;
			public RECT rcWork;
			public uint dwFlags;
		}
		
		[StructLayout(LayoutKind.Sequential)]
		public struct RECT {
			public int Left, Top, Right, Bottom;
			
			public RECT(int left, int top, int right, int bottom) {
				Left = left;
				Top = top;
				Right = right;
				Bottom = bottom;
			}
			
			public int X {
				get { return Left; }
				set {
					Right -= (Left - value);
					Left = value;
				}
			}
			
			public int Y {
				get { return Top; }
				set {
					Bottom -= (Top - value);
					Top = value;
				}
			}
			
			public int Height {
				get { return Bottom - Top; }
				set { Bottom = value + Top; }
			}
			
			public int Width {
				get { return Right - Left; }
				set { Right = value + Left; }
			}
		}
		
		[DllImport("user32.dll")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool GetTouchInputInfo(IntPtr hTouchInput, int cInputs, [Out] TOUCHINPUT[] pInputs, int cbSize);
		[StructLayout(LayoutKind.Sequential)]
		public struct TOUCHINPUT {
			public int x;
			public int y;
			public IntPtr hSource;
			public int dwID;
			public TOUCHINPUT_Flags dwFlags;
			public TOUCHINPUT_Mask dwMask;
			public int dwTime;
			public IntPtr dwExtraInfo;
			public int cxContact;
			public int cyContact;
		}
		[Flags]
		public enum TOUCHINPUT_Flags : int {
			TOUCHEVENTF_MOVE       = 0x0001,
			TOUCHEVENTF_DOWN       = 0x0002,
			TOUCHEVENTF_UP         = 0x0004,
			TOUCHEVENTF_INRANGE    = 0x0008,
			TOUCHEVENTF_PRIMARY    = 0x0010,
			TOUCHEVENTF_NOCOALESCE = 0x0020,
			TOUCHEVENTF_PEN        = 0x0040,
			TOUCHEVENTF_PALM       = 0x0080,
		}
		[Flags]
		public enum TOUCHINPUT_Mask : int {
			TOUCHINPUTMASKF_CONTACTAREA    = 0x0004,
			TOUCHINPUTMASKF_EXTRAINFO      = 0x0002,
			TOUCHINPUTMASKF_TIMEFROMSYSTEM = 0x0001,
		}

		[DllImport("user32.dll")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool GetPointerInfo(int pointerID, ref POINTER_INFO pPointerInfo);
		[StructLayout(LayoutKind.Sequential, Pack = 1)]
		public struct POINTER_INFO {
			public POINTER_INPUT_TYPE pointerType;
			public UInt32 pointerId;
			public UInt32 frameId;
			public POINTER_FLAGS pointerFlags;
			public IntPtr sourceDevice;
			public IntPtr hwndTarget;
			public POINT ptPixelLocation;
			public POINT ptHimetricLocation;
			public POINT ptPixelLocationRaw;
			public POINT ptHimetricLocationRaw;
			public UInt32 dwTime;
			public UInt32 historyCount;
			public Int32 inputData;
			public UInt32 dwKeyStates;
			public UInt64 PerformanceCount;
			public POINTER_BUTTON_CHANGE_TYPE ButtonChangeType;
		}
		public enum POINTER_INPUT_TYPE {
			PT_POINTER  = 0x00000001,
			PT_TOUCH    = 0x00000002,
			PT_PEN      = 0x00000003,
			PT_MOUSE    = 0x00000004,
			PT_TOUCHPAD = 0x00000005,
		}
		[Flags]
		public enum POINTER_FLAGS {
			POINTER_FLAG_NONE           = 0x00000000,
			POINTER_FLAG_NEW            = 0x00000001,
			POINTER_FLAG_INRANGE        = 0x00000002,
			POINTER_FLAG_INCONTACT      = 0x00000004,
			POINTER_FLAG_FIRSTBUTTON    = 0x00000010,
			POINTER_FLAG_SECONDBUTTON   = 0x00000020,
			POINTER_FLAG_THIRDBUTTON    = 0x00000040,
			POINTER_FLAG_FOURTHBUTTON   = 0x00000080,
			POINTER_FLAG_FIFTHBUTTON    = 0x00000100,
			POINTER_FLAG_PRIMARY        = 0x00002000,
			POINTER_FLAG_CONFIDENCE     = 0x00004000,
			POINTER_FLAG_CANCELED       = 0x00008000,
			POINTER_FLAG_DOWN           = 0x00010000,
			POINTER_FLAG_UPDATE         = 0x00020000,
			POINTER_FLAG_UP             = 0x00040000,
			POINTER_FLAG_WHEEL          = 0x00080000,
			POINTER_FLAG_HWHEEL         = 0x00100000,
			POINTER_FLAG_CAPTURECHANGED = 0x00200000,
			POINTER_FLAG_HASTRANSFORM   = 0x00400000,
		}
		public enum POINTER_BUTTON_CHANGE_TYPE {
			POINTER_CHANGE_NONE,
			POINTER_CHANGE_FIRSTBUTTON_DOWN,
			POINTER_CHANGE_FIRSTBUTTON_UP,
			POINTER_CHANGE_SECONDBUTTON_DOWN,
			POINTER_CHANGE_SECONDBUTTON_UP,
			POINTER_CHANGE_THIRDBUTTON_DOWN,
			POINTER_CHANGE_THIRDBUTTON_UP,
			POINTER_CHANGE_FOURTHBUTTON_DOWN,
			POINTER_CHANGE_FOURTHBUTTON_UP,
			POINTER_CHANGE_FIFTHBUTTON_DOWN,
			POINTER_CHANGE_FIFTHBUTTON_UP,
		}
		
		[StructLayout(LayoutKind.Sequential)]
		public struct POINT {
			public int X;
			public int Y;
		}
		
		[DllImport("user32.dll")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool GetPointerTouchInfo(int pointerId, ref POINTER_TOUCH_INFO touchInfo);
		[StructLayout(LayoutKind.Sequential)]
		public struct POINTER_TOUCH_INFO {
			public POINTER_INFO pointerInfo;
			public TOUCH_FLAGS  touchFlags;
			public TOUCH_MASK   touchMask;
			public RECT         rcContact;
			public RECT         rcContactRaw;
			public uint         orientation;
			public uint         pressure;
		}
		[Flags]
		public enum TOUCH_FLAGS {
			TOUCH_FLAG_NONE = 0x00000000,
		}
		[Flags]
		public enum TOUCH_MASK {
			TOUCH_MASK_NONE = 0x00000000,
			TOUCH_MASK_CONTACTAREA = 0x00000001,
			TOUCH_MASK_ORIENTATION = 0x00000002,
			TOUCH_MASK_PRESSURE = 0x00000004,
		}
		
		[DllImport("user32.dll")]
		public static extern IntPtr EnableMouseInPointer(bool value);

		[DllImport("kernel32.dll")]
		public static extern uint GetCurrentThreadId();
		[DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
		public static extern int GetClassName(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
		public delegate bool EnumWindowsProc(IntPtr hWnd,IntPtr lParam);
		[DllImport("user32.dll")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool EnumThreadWindows(uint dwThreadId, EnumWindowsProc lpEnumFunc, IntPtr lParam);
		
		[DllImport("user32.dll")]
		public static extern IntPtr MonitorFromWindow(IntPtr hwnd, uint dwFlags);
		
		[DllImport("user32.dll")]
		public static extern bool GetMonitorInfo(IntPtr hMonitor, ref MONITORINFO lpmi);
		
		[DllImport("user32.dll", EntryPoint = "SetWindowLong")]
		public static extern int SetWindowLong32(IntPtr hWnd, int nIndex, int dwNewLong);
		
		[DllImport("user32.dll", EntryPoint = "SetWindowLongPtr")]
		public static extern IntPtr SetWindowLongPtr64(IntPtr hWnd, int nIndex, IntPtr dwNewLong);
		
		[DllImport("user32.dll")]
		public static extern IntPtr CallWindowProc(IntPtr lpPrevWndFunc, IntPtr hWnd, uint msg, IntPtr wParam,
		                                           IntPtr lParam);
		
		[DllImport("user32.dll")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool RegisterTouchWindow(IntPtr hWnd, TOUCH_WINDOW_FLAGS ulFlags);
		[Flags]
		public enum TOUCH_WINDOW_FLAGS {
			TWF_FINETOUCH = 1,
			TWF_WANTPALM  = 2,
		}
		
		[DllImport("user32.dll")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool UnregisterTouchWindow(IntPtr hWnd);

		[DllImport("user32.dll")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern void CloseTouchInputHandle(IntPtr lParam);
		
		[DllImport("user32.dll")]
		public static extern bool ScreenToClient(IntPtr hWnd, ref POINT lpPoint);

		[DllImport("Kernel32.dll", CharSet = CharSet.Unicode)]
		public static extern ushort GlobalAddAtom(string lpString);
		
		[DllImport("Kernel32.dll")]
		public static extern ushort GlobalDeleteAtom(ushort nAtom);

		[DllImport("user32.dll", CharSet = CharSet.Unicode)]
		public static extern int SetProp(IntPtr hWnd, string lpString, int hData);

		[DllImport("user32.dll", CharSet = CharSet.Unicode)]
		public static extern int RemoveProp(IntPtr hWnd, string lpString);
		
		[DllImport("user32.dll", CharSet = CharSet.Auto)]
		public static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);

		[DllImport("kernel32.dll")]
		public static extern uint QueryPerformanceFrequency(out Int64 lpFrequency);

		[DllImport("kernel32.dll")]
		public static extern uint QueryPerformanceCounter(out Int64 lpPerformanceCount);
	}
}
