using System;
using System.Runtime.InteropServices;

using ALLEGRO_DISPLAY = System.IntPtr;
using ALLEGRO_JOYSTICK = System.IntPtr;
using ALLEGRO_KEYBOARD = System.IntPtr;
using ALLEGRO_MOUSE = System.IntPtr;
using ALLEGRO_TIMER = System.IntPtr;
using int64_t = System.Int64;
using ALLEGRO_USER_EVENT_DESCRIPTOR = System.IntPtr;
using intptr_t = System.IntPtr;

/* Type: ALLEGRO_EVENT_TYPE
 */
using ALLEGRO_EVENT_TYPE = System.UInt32;

/* Type: ALLEGRO_EVENT_QUEUE
 */
using ALLEGRO_EVENT_QUEUE = System.IntPtr;

namespace sharpallegro5
{
    /* event.h */
    public partial class AllegroApi
    {
        public const int ALLEGRO_EVENT_JOYSTICK_AXIS = 1;
        public const int ALLEGRO_EVENT_JOYSTICK_BUTTON_DOWN = 2;
        public const int ALLEGRO_EVENT_JOYSTICK_BUTTON_UP = 3;
        public const int ALLEGRO_EVENT_JOYSTICK_CONFIGURATION = 4;

        public const int ALLEGRO_EVENT_KEY_DOWN = 10;
        public const int ALLEGRO_EVENT_KEY_CHAR = 11;
        public const int ALLEGRO_EVENT_KEY_UP = 12;

        public const int ALLEGRO_EVENT_MOUSE_AXES = 20;
        public const int ALLEGRO_EVENT_MOUSE_BUTTON_DOWN = 21;
        public const int ALLEGRO_EVENT_MOUSE_BUTTON_UP = 22;
        public const int ALLEGRO_EVENT_MOUSE_ENTER_DISPLAY = 23;
        public const int ALLEGRO_EVENT_MOUSE_LEAVE_DISPLAY = 24;
        public const int ALLEGRO_EVENT_MOUSE_WARPED = 25;

        public const int ALLEGRO_EVENT_TIMER = 30;

        public const int ALLEGRO_EVENT_DISPLAY_EXPOSE = 40;
        public const int ALLEGRO_EVENT_DISPLAY_RESIZE = 41;
        public const int ALLEGRO_EVENT_DISPLAY_CLOSE = 42;
        public const int ALLEGRO_EVENT_DISPLAY_LOST = 43;
        public const int ALLEGRO_EVENT_DISPLAY_FOUND = 44;
        public const int ALLEGRO_EVENT_DISPLAY_SWITCH_IN = 45;
        public const int ALLEGRO_EVENT_DISPLAY_SWITCH_OUT = 46;
        public const int ALLEGRO_EVENT_DISPLAY_ORIENTATION = 47;


        /* Function: ALLEGRO_EVENT_TYPE_IS_USER
         *
         *    1 <= n < 512  - builtin events
         *  512 <= n < 1024 - reserved user events (for addons)
         * 1024 <= n        - unreserved user events
         */
        public static bool ALLEGRO_EVENT_TYPE_IS_USER(int t) { return ((t) >= 512); }


        /* Function: ALLEGRO_GET_EVENT_TYPE
         */
        public static int ALLEGRO_GET_EVENT_TYPE(int a, int b, int c, int d) { return AL_ID(a, b, c, d); }


        /* Type: ALLEGRO_EVENT_SOURCE
         */
        public unsafe struct ALLEGRO_EVENT_SOURCE
        {
            fixed int __pad[32];
        }



        /*
         * Event structures
         *
         * All event types have the following fields in common.
         *
         *  type      -- the type of event this is
         *  timestamp -- when this event was generated
         *  source    -- which event source generated this event
         *
         * For people writing event sources: The common fields must be at the
         * very start of each event structure, i.e. put _AL_EVENT_HEADER at the
         * front.
         */

        //#define _AL_EVENT_HEADER(srctype)                    \
        //   ALLEGRO_EVENT_TYPE type;                          \
        //   srctype *source;                                  \
        //   double timestamp;


        [StructLayout(LayoutKind.Explicit)]
        public struct ALLEGRO_ANY_EVENT
        {
            [FieldOffset(0)]
            public ALLEGRO_EVENT_TYPE type;
            [FieldOffset(4)]
            public IntPtr source;
            [FieldOffset(8)]
            public double timestamp;
        }


        [StructLayout(LayoutKind.Explicit)]
        public struct ALLEGRO_DISPLAY_EVENT
        {
            [FieldOffset(0)]
            public ALLEGRO_EVENT_TYPE type;
            [FieldOffset(4)]
            public IntPtr source;
            [FieldOffset(8)]
            public double timestamp;
            [FieldOffset(12)]
            public int x;
            [FieldOffset(16)]
            public int y;
            [FieldOffset(20)]
            public int width;
            [FieldOffset(24)]
            public int height;
            [FieldOffset(28)]
            public int orientation;
        }


        [StructLayout(LayoutKind.Explicit)]
        public struct ALLEGRO_JOYSTICK_EVENT
        {
            [FieldOffset(0)]
            public ALLEGRO_EVENT_TYPE type;
            [FieldOffset(4)]
            public IntPtr source;
            [FieldOffset(8)]
            public double timestamp;
            [FieldOffset(12)]
            public ALLEGRO_JOYSTICK id;
            [FieldOffset(16)]
            public int stick;
            [FieldOffset(20)]
            public int axis;
            [FieldOffset(24)]
            public float pos;
            [FieldOffset(28)]
            public int button;
        }



        [StructLayout(LayoutKind.Explicit)]
        public struct ALLEGRO_KEYBOARD_EVENT
        {
            [FieldOffset(0)]
            public ALLEGRO_EVENT_TYPE type;
            [FieldOffset(4)]
            public IntPtr source;
            [FieldOffset(8)]
            public double timestamp;
            [FieldOffset(12)]
            public ALLEGRO_DISPLAY display; /* the window the key was pressed in */
            [FieldOffset(16)]
            public int keycode;                 /* the physical key pressed */
            [FieldOffset(20)]
            public int unichar;                 /* unicode character or negative */
            [FieldOffset(24)]
            public uint modifiers;      /* bitfield */
            [FieldOffset(28)]
            public bool repeat;                 /* auto-repeated or not */
        }



        [StructLayout(LayoutKind.Explicit)]
        public struct ALLEGRO_MOUSE_EVENT
        {
            [FieldOffset(0)]
            public ALLEGRO_EVENT_TYPE type;
            [FieldOffset(4)]
            public IntPtr source;
            [FieldOffset(8)]
            public double timestamp;
            [FieldOffset(12)]
            public ALLEGRO_DISPLAY display;
            /* (display) Window the event originate from
             * (x, y) Primary mouse position
             * (z) Mouse wheel position (1D 'wheel'), or,
             * (w, z) Mouse wheel position (2D 'ball')
             * (pressure) The pressure applied, for stylus (0 or 1 for normal mouse)
             */
            [FieldOffset(16)]
            public int x;
            [FieldOffset(20)]
            public int y;
            [FieldOffset(24)]
            public int z;
            [FieldOffset(28)]
            public int w;
            [FieldOffset(32)]
            public int dx;
            [FieldOffset(36)]
            public int dy;
            [FieldOffset(40)]
            public int dz;
            [FieldOffset(44)]
            public int dw;
            [FieldOffset(48)]
            public uint button;
            [FieldOffset(52)]
            public float pressure;
        }



        [StructLayout(LayoutKind.Explicit)]
        public struct ALLEGRO_TIMER_EVENT
        {
            [FieldOffset(0)]
            public ALLEGRO_EVENT_TYPE type;
            [FieldOffset(4)]
            public IntPtr source;
            [FieldOffset(8)]
            public double timestamp;
            [FieldOffset(16)]
            public int64_t count;
            [FieldOffset(24)]
            public double error;
        }



        /* Type: ALLEGRO_USER_EVENT
         */
        [StructLayout(LayoutKind.Explicit)]
        public struct ALLEGRO_USER_EVENT
        {
            [FieldOffset(0)]
            ALLEGRO_EVENT_TYPE type;
            [FieldOffset(4)]
            IntPtr source;
            [FieldOffset(8)]
            double timestamp;
            [FieldOffset(12)]
            ALLEGRO_USER_EVENT_DESCRIPTOR __internal__descr;
            [FieldOffset(16)]
            intptr_t data1;
            [FieldOffset(20)]
            intptr_t data2;
            [FieldOffset(24)]
            intptr_t data3;
            [FieldOffset(28)]
            intptr_t data4;
        }



        /* Type: ALLEGRO_EVENT
         */
        [StructLayout(LayoutKind.Explicit)]
        public struct ALLEGRO_EVENT
        {
            /* This must be the same as the first field of _AL_EVENT_HEADER.  */
            [FieldOffset(0)]
            public ALLEGRO_EVENT_TYPE type;
            /* `any' is to allow the user to access the other fields which are
             * common to all event types, without using some specific type
             * structure.
             */
            [FieldOffset(4)]
            public ALLEGRO_ANY_EVENT any;
            [FieldOffset(4)]
            public ALLEGRO_DISPLAY_EVENT display;
            [FieldOffset(4)]
            public ALLEGRO_JOYSTICK_EVENT joystick;
            [FieldOffset(4)]
            public ALLEGRO_KEYBOARD_EVENT keyboard;
            [FieldOffset(4)]
            public ALLEGRO_MOUSE_EVENT mouse;
            [FieldOffset(4)]
            public ALLEGRO_TIMER_EVENT timer;
            [FieldOffset(4)]
            public ALLEGRO_USER_EVENT user;
        }



        /* Event sources */

        [DllImport(allegroDllName, CallingConvention = CallingConvention.Cdecl)]
        public static extern void al_init_user_event_source(ALLEGRO_EVENT_SOURCE source);
        [DllImport(allegroDllName, CallingConvention = CallingConvention.Cdecl)]
        public static extern void al_destroy_user_event_source(ALLEGRO_EVENT_SOURCE source);
        /* The second argument is ALLEGRO_EVENT instead of ALLEGRO_USER_EVENT
         * to prevent users passing a pointer to a too-short structure.
         */
        //        [DllImport(allegroDllName, CallingConvention = CallingConvention.Cdecl)]
        //public static extern bool al_emit_user_event(ALLEGRO_EVENT_SOURCE source, ALLEGRO_EVENT ret_event, void (*dtor)(ALLEGRO_USER_EVENT *));
        [DllImport(allegroDllName, CallingConvention = CallingConvention.Cdecl)]
        public static extern void al_unref_user_event(ALLEGRO_USER_EVENT usr_event);
        [DllImport(allegroDllName, CallingConvention = CallingConvention.Cdecl)]
        public static extern void al_set_event_source_data(ALLEGRO_EVENT_SOURCE source, intptr_t data);
        [DllImport(allegroDllName, CallingConvention = CallingConvention.Cdecl)]
        public static extern intptr_t al_get_event_source_data(ALLEGRO_EVENT_SOURCE source);



        /* Event queues */

        [DllImport(allegroDllName, CallingConvention = CallingConvention.Cdecl)]
        public static extern ALLEGRO_EVENT_QUEUE al_create_event_queue();
        [DllImport(allegroDllName, CallingConvention = CallingConvention.Cdecl)]
        public static extern void al_destroy_event_queue(ALLEGRO_EVENT_QUEUE queue);
        [DllImport(allegroDllName, CallingConvention = CallingConvention.Cdecl)]
        public static extern void al_register_event_source(ALLEGRO_EVENT_QUEUE queue, IntPtr source);
        [DllImport(allegroDllName, CallingConvention = CallingConvention.Cdecl)]
        public static extern void al_unregister_event_source(ALLEGRO_EVENT_QUEUE queue, ALLEGRO_EVENT_SOURCE source);
        [DllImport(allegroDllName, CallingConvention = CallingConvention.Cdecl)]
        public static extern bool al_is_event_queue_empty(ALLEGRO_EVENT_QUEUE queue);
        [DllImport(allegroDllName, CallingConvention = CallingConvention.Cdecl)]
        public static extern bool al_get_next_event(ALLEGRO_EVENT_QUEUE queue, ref ALLEGRO_EVENT ret_event);
        [DllImport(allegroDllName, CallingConvention = CallingConvention.Cdecl)]
        public static extern bool al_peek_next_event(ALLEGRO_EVENT_QUEUE queue, ref ALLEGRO_EVENT ret_event);
        [DllImport(allegroDllName, CallingConvention = CallingConvention.Cdecl)]
        public static extern bool al_drop_next_event(ALLEGRO_EVENT_QUEUE queue);
        [DllImport(allegroDllName, CallingConvention = CallingConvention.Cdecl)]
        public static extern void al_flush_event_queue(ALLEGRO_EVENT_QUEUE queue);
        [DllImport(allegroDllName, CallingConvention = CallingConvention.Cdecl)]
        public static extern void al_wait_for_event(ALLEGRO_EVENT_QUEUE queue, ref ALLEGRO_EVENT ret_event);
        [DllImport(allegroDllName, CallingConvention = CallingConvention.Cdecl)]
        public static extern bool al_wait_for_event_timed(ALLEGRO_EVENT_QUEUE queue, ref ALLEGRO_EVENT ret_event, float secs);
        [DllImport(allegroDllName, CallingConvention = CallingConvention.Cdecl)]
        public static extern bool al_wait_for_event_until(ALLEGRO_EVENT_QUEUE queue, ref ALLEGRO_EVENT ret_event, ALLEGRO_TIMEOUT timeout);
    }
}
