using System;

using sharpallegro5;
using System.Runtime.InteropServices;

using ALLEGRO_CONFIG = System.IntPtr;
using ALLEGRO_EVENT_QUEUE = System.IntPtr;
using ALLEGRO_FONT = System.IntPtr;
using ALLEGRO_DISPLAY = System.IntPtr;

/* Tests vsync.
 */
public class ex_vsync : AllegroExample
{
    static int vsync, fullscreen, frequency;

    static int option(IntPtr config, string name, int v)
    {
        string value;
        string str;
        value = al_get_config_value(config, "settings", name);
        if (value != null)
            v = int.Parse(value);
        str = string.Format("{0}", v);
        al_set_config_value(config, "settings", name, str);
        return v;
    }

    static bool display_warning(ALLEGRO_EVENT_QUEUE queue, ALLEGRO_FONT font)
    {
        ALLEGRO_EVENT @event = new ALLEGRO_EVENT();
        float x = 320.0f;
        float h = al_get_font_line_height(font);
        ALLEGRO_COLOR white = al_map_rgb_f(1, 1, 1);

        for (; ; )
        {
            float y = 200.0f;
            al_clear_to_color(al_map_rgb(0, 0, 0));
            al_draw_text(font, white, x, y, ALLEGRO_ALIGN_CENTRE,
               "Do not continue if you suffer from photosensitive epilepsy", __arglist());
            al_draw_text(font, white, x, y + 15, ALLEGRO_ALIGN_CENTRE,
               "or simply hate flashing screens.", __arglist());
            al_draw_text(font, white, x, y + 40, ALLEGRO_ALIGN_CENTRE,
               "Press Escape to quit or Enter to continue.", __arglist());

            y += 100;
            al_draw_text(font, white, x, y, ALLEGRO_ALIGN_CENTRE, "Parameters from ex_vsync.ini:", __arglist());
            y += h;
            al_draw_textf(font, white, x, y, ALLEGRO_ALIGN_CENTRE, "vsync: %d", __arglist(vsync));
            y += h;
            al_draw_textf(font, white, x, y, ALLEGRO_ALIGN_CENTRE, "fullscreen: %d", __arglist(fullscreen));
            y += h;
            al_draw_textf(font, white, x, y, ALLEGRO_ALIGN_CENTRE, "frequency: %d", __arglist(frequency));

            al_flip_display();

            al_wait_for_event(queue, ref @event);
            if (@event.type == ALLEGRO_EVENT_KEY_DOWN)
            {
                if (@event.keyboard.keycode == ALLEGRO_KEY_ESCAPE)
                {
                    return true;
                }
                if (@event.keyboard.keycode == ALLEGRO_KEY_ENTER)
                {
                    return false;
                }
            }
            if (@event.type == ALLEGRO_EVENT_DISPLAY_CLOSE)
            {
                return true;
            }
        }
    }

    static int Main()
    {
        ALLEGRO_DISPLAY display;
        ALLEGRO_FONT font;
        IntPtr config;
        ALLEGRO_EVENT_QUEUE queue;
        bool write = false;
        bool flip = false;
        bool quit;

        if (!al_init())
        {
            Console.WriteLine("Could not init Allegro.\n");
            return 1;
        }

        al_init_font_addon();
        al_init_image_addon();
        al_install_keyboard();
        al_install_mouse();

        /* Read parameters from ex_vsync.ini. */
        config = al_load_config_file("ex_vsync.ini");
        if (config == IntPtr.Zero)
        {
            config = al_create_config();
            write = true;
        }

        /* 0 -> Driver chooses.
         * 1 -> Force vsync on.
         * 2 -> Force vsync off.
         */
        vsync = option(config, "vsync", 0);

        fullscreen = option(config, "fullscreen", 0);
        frequency = option(config, "frequency", 0);

        /* Write the file back (so a template is generated on first run). */
        if (write)
        {
            al_save_config_file("ex_vsync.ini", config);
        }
        al_destroy_config(config);

        /* Vsync 1 means force on, 2 means forced off. */
        if (vsync > 0)
            al_set_new_display_option(ALLEGRO_VSYNC, vsync, ALLEGRO_SUGGEST);

        /* Force fullscreen mode. */
        if (fullscreen > 0)
        {
            al_set_new_display_flags(ALLEGRO_FULLSCREEN);
            /* Set a monitor frequency. */
            if (frequency > 0)
                al_set_new_display_refresh_rate(frequency);
        }

        display = al_create_display(640, 480);
        if (display == IntPtr.Zero)
        {
            Console.WriteLine("Error creating display.\n");
            return 1;
        }

        font = al_load_font("data/a4_font.tga", 0, 0);
        if (font == IntPtr.Zero)
        {
            abort_example("Failed to load a4_font.tga\n");
            return 1;
        }

        queue = al_create_event_queue();
        al_register_event_source(queue, al_get_keyboard_event_source());
        al_register_event_source(queue, al_get_mouse_event_source());
        al_register_event_source(queue, al_get_display_event_source(display));

        quit = display_warning(queue, font);
        al_flush_event_queue(queue);

        while (!quit)
        {
            ALLEGRO_EVENT @event = new ALLEGRO_EVENT();

            /* With vsync, this will appear as a 50% gray screen (maybe
             * flickering a bit depending on monitor frequency).
             * Without vsync, there will be black/white shearing all over.
             */
            if (flip)
                al_clear_to_color(al_map_rgb_f(1, 1, 1));
            else
                al_clear_to_color(al_map_rgb_f(0, 0, 0));

            al_flip_display();

            flip = !flip;

            while (al_get_next_event(queue, ref @event))
            {
                switch (@event.type)
                {
                    case ALLEGRO_EVENT_DISPLAY_CLOSE:
                        quit = true;
                        break;

                    case ALLEGRO_EVENT_KEY_DOWN:
                        if (@event.keyboard.keycode == ALLEGRO_KEY_ESCAPE)
                            quit = true;
                        break;
                }
            }
            /* Let's not go overboard and limit flipping at 1000 Hz. Without
             * this my system locks up and requires a hard reboot :P
             */
            al_rest(0.001);
        }

        al_destroy_font(font);
        al_destroy_event_queue(queue);

        return 0;
    }
}