﻿/*
	This file is part of SDL-CS-GUI.

	SDL-CS-GUI is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	SDL-CS-GUI is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with SDL-CS-GUI.  If not, see <http://www.gnu.org/licenses/>.
*/

using System;
using System.Collections.Generic;

using SDL2;

using SDL2_CS_GUI.Components;

namespace SDL2_CS_GUI
{
	public delegate bool OnClick(Component Sender, SDL.SDL_MouseButtonEvent SDL_MouseButtonEvent, Point Point);
	public delegate bool OnQuit(SDL.SDL_QuitEvent SDL_QuitEvent);
	public delegate bool OnTextInput(SDL.SDL_TextInputEvent SDL_TextInputEvent);
	public delegate bool OnKeyboardPress(SDL.SDL_KeyboardEvent SDL_KeyboardEvent);
	public delegate bool OnMouseWheelEvent(Component Sender, SDL.SDL_MouseWheelEvent SDL_MouseWheelEvent, Point Point);

	public static class EventManager
	{
		public static readonly List<Window> Windows;
		
		static EventManager()
		{
			Windows = new List<Window>();
		}

		#region Methods
		public static void HandleEvents()
		{
			SDL.SDL_Event SDL_Event;
			SDL.SDL_PollEvent(out SDL_Event);
			EventManager.HandleEvent(SDL_Event);
		}

		public static bool IsPointInRectangle(Point Point, Rectangle Rectangle)
		{
			if (Rectangle == null)
				return false;

			if ((Point.X > Rectangle.X) && ((Rectangle.X + Rectangle.W) > Point.X))
				if ((Point.Y > Rectangle.Y) && ((Rectangle.Y + Rectangle.H) > Point.Y))
					return true;

			return false;
		}

		public static bool RectangleBetweenPoints(Point TopLeft, Point BottomRight, Rectangle Rectangle)
		{
			if ((TopLeft.X <= Rectangle.X) && (TopLeft.Y <= Rectangle.Y))
				if ((BottomRight.X >= (Rectangle.X + Rectangle.W)) && (BottomRight.Y >= (Rectangle.Y + Rectangle.H)))
					return true;

			return false;
		}

		public static bool KeyPressed(SDL.SDL_Scancode SDL_Scancode)
		{
			int Result;
			IntPtr ArrayPointer = SDL.SDL_GetKeyboardState(out Result);
			unsafe
			{
				void* Array = ArrayPointer.ToPointer();
				byte* KeyArrayPointer = ((byte*) Array);
				byte Key = (*(KeyArrayPointer + ((int) SDL_Scancode)));
				return !(Key == 0);
			}
		}

		private static void HandleEvent(SDL.SDL_Event SDL_Event)
		{
			Point Point = new Point();
			uint WindowID;

			switch (SDL_Event.type)
			{
				case SDL.SDL_EventType.SDL_MOUSEBUTTONDOWN:
					WindowID = SDL_Event.button.windowID;
					Point.AbsoluteXPosition = true;
					Point.AbsoluteYPosition = true;
					Point.X = SDL_Event.button.x;
					Point.Y = SDL_Event.button.y;

					Window Window = Windows.Find(W => SDL.SDL_GetWindowID(W.SDL_Window).Equals(WindowID));
					if (Window != null)
						Window.OnClick(Window, SDL_Event.button, Point);

					break;
				case SDL.SDL_EventType.SDL_QUIT:
					SDL.SDL_QuitEvent SDL_QuitEvent = SDL_Event.quit;
					try
					{
						Windows.ForEach(W => W.OnQuitEvent(SDL_QuitEvent));
						Windows.ForEach(W => W.Dispose());
					}
					catch
					{
						// Ignore this, we are probably quitting anyway
					}

					break;
				case SDL.SDL_EventType.SDL_TEXTINPUT:
					SDL.SDL_TextInputEvent SDL_TextInputEvent = SDL_Event.text;
					WindowID = SDL_TextInputEvent.windowID;
					Window = EventManager.Windows.Find(W => SDL.SDL_GetWindowID(W.SDL_Window).Equals(WindowID));
					if (Window != null)
						Window.OnTextInputEvent(SDL_TextInputEvent);

					break;
				case SDL.SDL_EventType.SDL_KEYDOWN:
					SDL.SDL_KeyboardEvent SDL_KeyboardEvent = SDL_Event.key;
					WindowID = SDL_KeyboardEvent.windowID;
					Window = EventManager.Windows.Find(W => SDL.SDL_GetWindowID(W.SDL_Window).Equals(WindowID));
					if (Window != null)
						Window.OnKeyboardPressEvent(SDL_KeyboardEvent);

					break;
				case SDL.SDL_EventType.SDL_MOUSEWHEEL:
					Window = EventManager.Windows.Find(W => true); // Just "the first"
					if (Window == null)
					{
						break;
					}

					int MousePositionX, MousePositionY;
					SDL.SDL_GetMouseState(out MousePositionX, out MousePositionY);
					Point = new Point() { X = MousePositionX, Y = MousePositionY, AbsoluteXPosition = true, AbsoluteYPosition = true };

					if (!Window.Fullscreen)
					{
						if (MousePositionX >= (Window.Width - 1))
							break;

						if (MousePositionY >= (Window.Height - 1))
							break;

						if ((Point.X < 1) || (Point.Y < 1))
							break;
					}

					SDL.SDL_MouseWheelEvent SDL_MouseWheelEvent = SDL_Event.wheel;
					WindowID = SDL_MouseWheelEvent.windowID;
					Window = EventManager.Windows.Find(W => SDL.SDL_GetWindowID(W.SDL_Window).Equals(WindowID));

					if (Window != null)
						Window.OnMouseWheelEvent(Window, SDL_MouseWheelEvent, Point);

					break;
			}
		}
		#endregion
	}
}
