using SDL2;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SDL2Demo.SdlWrapper;
using static SDL2.SDL;

namespace testdrid.SdlWrapper
{
    internal class EventPoller
    {
        public static EventPoller GetInstance()
        {
            if (singleton == null)
            {
                singleton = new EventPoller();
            }

            return singleton;
        }

        private EventPoller()
        {
        }
        
        private static EventPoller singleton;
        private SDL_Event sdlEvent;
        public IEventConsumer Junction { get; set; }
        public void PollEvents()
        {
            while (SDL.SDL_PollEvent(out sdlEvent) != 0)
            {
                Junction.ProcessEvent(sdlEvent);
                switch (sdlEvent.type)
                {
                    case SDL_EventType.SDL_AUDIODEVICEADDED:
                        SDL_AudioDeviceEvent sdlAudioDeviceEvent = sdlEvent.adevice;
                        AudioDeviceAdded?.Invoke(sdlAudioDeviceEvent);
                        break;
                    case SDL_EventType.SDL_WINDOWEVENT:
                        SDL_WindowEvent sdlWindowEvent = sdlEvent.window;
                        switch (sdlWindowEvent.windowEvent)
                        {
                            case SDL_WindowEventID.SDL_WINDOWEVENT_SHOWN:
                                WindowShown?.Invoke(sdlWindowEvent);
                                break;
                            case SDL_WindowEventID.SDL_WINDOWEVENT_FOCUS_GAINED:
                                WindowFocusGained?.Invoke(sdlWindowEvent);
                                break;
                            case SDL_WindowEventID.SDL_WINDOWEVENT_EXPOSED:
                                WindowExposed?.Invoke(sdlWindowEvent);
                                break;
                            case SDL_WindowEventID.SDL_WINDOWEVENT_CLOSE:
                                WindowClose?.Invoke(sdlWindowEvent);
                                break;
                            case SDL_WindowEventID.SDL_WINDOWEVENT_ENTER:
                                WindowEnteredByMouseCursor?.Invoke(sdlWindowEvent);
                                break;
                            case SDL_WindowEventID.SDL_WINDOWEVENT_LEAVE:
                                WindowLeftByMouseCursor?.Invoke(sdlWindowEvent);
                                break;
                            case SDL_WindowEventID.SDL_WINDOWEVENT_FOCUS_LOST:
                                WindowFocusGained?.Invoke(sdlWindowEvent);
                                break;
                            case SDL_WindowEventID.SDL_WINDOWEVENT_MOVED:
                                WindowMoved?.Invoke(sdlWindowEvent);
                                break;
                            case SDL_WindowEventID.SDL_WINDOWEVENT_HIDDEN:
                                WindowHidden?.Invoke(sdlWindowEvent);
                                break;
                            case SDL_WindowEventID.SDL_WINDOWEVENT_SIZE_CHANGED:
                                WindowSizeChanged?.Invoke(sdlWindowEvent);
                                break;
                            case SDL_WindowEventID.SDL_WINDOWEVENT_MINIMIZED:
                                WindowMinimized?.Invoke(sdlWindowEvent);
                                break;
                            case SDL_WindowEventID.SDL_WINDOWEVENT_RESIZED:
                                WindowResized?.Invoke(sdlWindowEvent);
                                break;
                            case SDL_WindowEventID.SDL_WINDOWEVENT_RESTORED:
                                WindowResized?.Invoke(sdlWindowEvent);
                                break;
                            case SDL_WindowEventID.SDL_WINDOWEVENT_ICCPROF_CHANGED:
                                WindowIccProfileChanged?.Invoke(sdlWindowEvent);
                                break;
                            default:
                                Console.WriteLine(sdlWindowEvent.windowEvent.ToString());
                                throw new NotImplementedException(sdlWindowEvent.windowEvent.ToString());
                        }
                        break;
                    case SDL_EventType.SDL_TEXTEDITING:
                        SDL_TextEditingEvent sdlTextEditingEvent = sdlEvent.edit;
                        TextEditing?.Invoke(sdlTextEditingEvent);
                        break;
                    case SDL_EventType.SDL_MOUSEMOTION:
                        SDL_MouseMotionEvent sdlMouseMotionEvent = sdlEvent.motion;
                        MouseMotion?.Invoke(sdlMouseMotionEvent);
                        break;
                    case SDL_EventType.SDL_QUIT:
                        SDL_QuitEvent sdlQuitEvent = sdlEvent.quit;
                        Quit?.Invoke(sdlQuitEvent);
                        break;
                    case SDL_EventType.SDL_MOUSEBUTTONDOWN:
                        SDL_MouseButtonEvent sdlMouseButtonEvent = sdlEvent.button;
                        MouseButtonDown?.Invoke(sdlMouseButtonEvent);
                        break;
                    case SDL_EventType.SDL_MOUSEBUTTONUP:
                        SDL_MouseButtonEvent sdlMouseButtonEvent2 = sdlEvent.button;
                        MouseButtonUp?.Invoke(sdlMouseButtonEvent2);
                        break;
                    case SDL_EventType.SDL_MOUSEWHEEL:
                        SDL_MouseWheelEvent sdlMouseWheelEvent = sdlEvent.wheel;
                        MouseWheel?.Invoke(sdlMouseWheelEvent);
                        break;
                    case SDL_EventType.SDL_CLIPBOARDUPDATE:
                        ClipboardUpdate?.Invoke();
                        break;
                    case SDL_EventType.SDL_KEYDOWN:
                        SDL_KeyboardEvent sdlKeyboardEvent = sdlEvent.key;
                        KeyDown?.Invoke(sdlKeyboardEvent);
                        break;
                    case SDL_EventType.SDL_TEXTINPUT:
                        SDL_TextInputEvent sdlTextInputEvent = sdlEvent.text;
                        TextInput?.Invoke(sdlTextInputEvent);
                        break;
                    case SDL_EventType.SDL_KEYUP:
                        SDL_KeyboardEvent sdlEventKey = sdlEvent.key;
                        KeyUp?.Invoke(sdlEventKey);
                        break;
                    case SDL_EventType.SDL_RENDER_TARGETS_RESET:
                        RenderTargetsReset?.Invoke(sdlEvent);
                        break;
                    case SDL_EventType.SDL_DISPLAYEVENT:
                        switch (sdlEvent.display.displayEvent)
                        {
                            case SDL_DisplayEventID.SDL_DISPLAYEVENT_CONNECTED:
                                DisplayConnected?.Invoke(sdlEvent.display);
                                break;
                            case SDL_DisplayEventID.SDL_DISPLAYEVENT_DISCONNECTED:
                                DisplayDisconnected?.Invoke(sdlEvent.display);
                                break;
                            default:
                                throw new NotImplementedException(sdlEvent.display.displayEvent.ToString());
                        }
                        break;
                    case SDL_EventType.SDL_DROPBEGIN:
                        DropBegin?.Invoke(sdlEvent.drop);
                        break;
                    case SDL_EventType.SDL_JOYDEVICEADDED:
	                    JoystickDeviceAdded?.Invoke(sdlEvent.jdevice);
	                    break;
                    case SDL_EventType.SDL_CONTROLLERDEVICEADDED:
	                    ControllerDeviceAdded?.Invoke(sdlEvent.cdevice);
	                    break;
                    case SDL_EventType.SDL_AUDIODEVICEREMOVED:
                        AudioDeviceRemoved?.Invoke(sdlEvent.adevice);
                        break;
                    default:
                        Console.WriteLine(sdlEvent.type.ToString());
                        throw new NotImplementedException(sdlEvent.type.ToString());
                }
            }
        }

        public delegate void ControllerDeviceDelegate(SDL_ControllerDeviceEvent cde);
        public event ControllerDeviceDelegate ControllerDeviceAdded;

        public delegate void JoystickDeviceDelegate(SDL_JoyDeviceEvent jde);
        public event JoystickDeviceDelegate JoystickDeviceAdded;

        public delegate void DropEventDelegate(SDL_DropEvent de);
        public event DropEventDelegate DropBegin;

        public delegate void DisplayEventDelegate(SDL_DisplayEvent de);
        public event DisplayEventDelegate DisplayConnected;
        public event DisplayEventDelegate DisplayDisconnected;

        public delegate void AudioDeviceEventDelegate(SDL_AudioDeviceEvent ade);
        public event AudioDeviceEventDelegate AudioDeviceAdded;
        public event AudioDeviceEventDelegate AudioDeviceRemoved;

        public delegate void WindowEventDelegate(SDL_WindowEvent we);
        public event WindowEventDelegate WindowShown;

        public event WindowEventDelegate WindowFocusGained;

        public delegate void TextEditingEventDelegate(SDL_TextEditingEvent tee);
        public event TextEditingEventDelegate TextEditing;

        public event WindowEventDelegate WindowExposed;

        public event WindowEventDelegate WindowClose;

        public event WindowEventDelegate WindowEnteredByMouseCursor;

        public delegate void MouseMotionEventDelegate(SDL_MouseMotionEvent mme);
        public event MouseMotionEventDelegate MouseMotion;

        public event WindowEventDelegate WindowLeftByMouseCursor;

        public delegate void QuitEventDelegate(SDL_QuitEvent qe);
        public event QuitEventDelegate Quit;

        public event WindowEventDelegate WindowFocusLost;

        public event WindowEventDelegate WindowMoved;

        public event WindowEventDelegate WindowHidden;

        public event WindowEventDelegate WindowIccProfileChanged;

        public delegate void MouseButtonEventDelegate(SDL_MouseButtonEvent mbe);
        public event MouseButtonEventDelegate MouseButtonDown;

        public event MouseButtonEventDelegate MouseButtonUp;

        public delegate void MouseWheelEventDelegate(SDL_MouseWheelEvent mwe);
        public event MouseWheelEventDelegate MouseWheel;

        public delegate void ClipboardUpdateDelegate();
        public event ClipboardUpdateDelegate ClipboardUpdate;

        public delegate void KeyboardEventDelegate(SDL_KeyboardEvent ke);
        public event KeyboardEventDelegate KeyDown;

        public delegate void TextInputEventDelegate(SDL_TextInputEvent tie);
        public event TextInputEventDelegate TextInput;

        public event KeyboardEventDelegate KeyUp;

        public event WindowEventDelegate WindowSizeChanged;

        public delegate void InformalEventDelegate(SDL_Event sdlEvent);
        public event InformalEventDelegate RenderTargetsReset;

        public event WindowEventDelegate WindowMinimized;

        public event WindowEventDelegate WindowResized;

        public event WindowEventDelegate WindowRestored;
    }
}
