using System;
using System.Text;

using sharpallegro5;

using ALLEGRO_DISPLAY = System.IntPtr;
using ALLEGRO_BITMAP = System.IntPtr;
using ALLEGRO_TIMER = System.IntPtr;
using ALLEGRO_EVENT_QUEUE = System.IntPtr;
using ALLEGRO_FONT = System.IntPtr;

public class ex_keyboard_events : AllegroExample
{
    /*
     *    Example program for the Allegro library, by Peter Wang.
     *    Updated by Ryan Dickie.
     *
     *    This program tests keyboard events.
     */


    const int WIDTH = 640;
    const int HEIGHT = 480;
    const int SIZE_LOG = 50;


    /* globals */
    static ALLEGRO_EVENT_QUEUE event_queue;
    static ALLEGRO_DISPLAY display;



    static void log_key(string how, int keycode, int unichar, int modifiers)
    {
        StringBuilder multibyte = new StringBuilder();
        string key_name;

        al_utf8_encode(multibyte, unichar <= 32 ? ' ' : unichar);
        key_name = al_keycode_to_name(keycode);
        log_printf("{0,-8}  code={1:000}, char='{2}' ({3,4}), modifiers={4:x8}, [{5}]\n",
           how, keycode, multibyte, unichar, modifiers, key_name);
    }

    /* main_loop:
     *  The main loop of the program.  Here we wait for events to come in from
     *  any one of the event sources and react to each one accordingly.  While
     *  there are no events to react to the program sleeps and consumes very
     *  little CPU time.  See main() to see how the event sources and event queue
     *  are set up.
     */
    static void main_loop()
    {
        ALLEGRO_EVENT @event = new ALLEGRO_EVENT();

        log_printf("Focus on the main window (black) and press keys to see events. ");
        log_printf("Escape quits.\n\n");

        while (true)
        {
            /* Take the next event out of the event queue, and store it in `event'. */
            al_wait_for_event(event_queue, ref @event);

            /* Check what type of event we got and act accordingly.  ALLEGRO_EVENT
             * is a union type and interpretation of its contents is dependent on
             * the event type, which is given by the 'type' field.
             *
             * Each event also comes from an event source and has a timestamp.
             * These are accessible through the 'any.source' and 'any.timestamp'
             * fields respectively, e.g. 'event.any.timestamp'
             */
            switch (@event.type)
            {

                /* ALLEGRO_EVENT_KEY_DOWN - a keyboard key was pressed.
                 */
                case ALLEGRO_EVENT_KEY_DOWN:
                    if (@event.keyboard.keycode == ALLEGRO_KEY_ESCAPE)
                    {
                        return;
                    }
                    log_key("KEY_DOWN", @event.keyboard.keycode, 0, 0);
                    break;

                /* ALLEGRO_EVENT_KEY_UP - a keyboard key was released.
                 */
                case ALLEGRO_EVENT_KEY_UP:
                    log_key("KEY_UP", @event.keyboard.keycode, 0, 0);
                    break;

                /* ALLEGRO_EVENT_KEY_CHAR - a character was typed or repeated.
                 */
                case ALLEGRO_EVENT_KEY_CHAR:
                    {
                        string label = (@event.keyboard.repeat ? "repeat" : "KEY_CHAR");
                        log_key(label,
                           @event.keyboard.keycode,
                           @event.keyboard.unichar,
                           (int)@event.keyboard.modifiers);
                        break;
                    }

                /* ALLEGRO_EVENT_DISPLAY_CLOSE - the window close button was pressed.
                 */
                case ALLEGRO_EVENT_DISPLAY_CLOSE:
                    return;

                /* We received an event of some type we don't know about.
                 * Just ignore it.
                 */
                default:
                    break;
            }
        }
    }



    static int Main()
    {
        if (!al_init())
        {
            abort_example("Could not init Allegro.\n");
            return 1;
        }

        open_log_monospace();

        display = al_create_display(WIDTH, HEIGHT);
        if (display == IntPtr.Zero)
        {
            abort_example("al_create_display failed\n");
            return 1;
        }

        if (!al_install_keyboard())
        {
            abort_example("al_install_keyboard failed\n");
            return 1;
        }

        event_queue = al_create_event_queue();
        if (event_queue == IntPtr.Zero)
        {
            abort_example("al_create_event_queue failed\n");
            return 1;
        }

        al_register_event_source(event_queue, al_get_keyboard_event_source());
        al_register_event_source(event_queue, al_get_display_event_source(display));

        main_loop();

        close_log(false);

        return 0;
    }
}