using System;

using sharpallegro5;

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

/*
 *    Example program for the Allegro library.
 *
 *    This program blitting to/from sub-bitmaps.
 *
 */
public class ex_subbitmap : AllegroExample
{
    static int MIN(int x, int y) { return (((x) < (y)) ? (x) : (y)); }
    static int MAX(int x, int y) { return (((x) > (y)) ? (x) : (y)); }
    static int CLAMP(int x, int y, int z) { return MAX((x), MIN((y), (z))); }

    enum Mode
    {
        PLAIN_BLIT,
        SCALED_BLIT
    };

    const int SRC_WIDTH = 640;
    const int SRC_HEIGHT = 480;
    const int SRC_X = 160;
    const int SRC_Y = 120;
    const int DST_WIDTH = 640;
    const int DST_HEIGHT = 480;


    static ALLEGRO_DISPLAY src_display;
    static ALLEGRO_DISPLAY dst_display;
    static ALLEGRO_EVENT_QUEUE queue;
    static ALLEGRO_BITMAP src_bmp;

    static int src_x1 = SRC_X;
    static int src_y1 = SRC_Y;
    static int src_x2 = SRC_X + 319;
    static int src_y2 = SRC_Y + 199;
    static int dst_x1 = 0;
    static int dst_y1 = 0;
    static int dst_x2 = DST_WIDTH - 1;
    static int dst_y2 = DST_HEIGHT - 1;

    static Mode mode = Mode.PLAIN_BLIT;
    static int draw_flags = 0;

    static void SWAP_GREATER(ref float f1, ref float f2)
    {
        if (f1 > f2)
        {
            float tmp = f1;
            f1 = f2;
            f2 = tmp;
        }
    }

    static int Main(string[] argv)
    {
        ALLEGRO_BITMAP[] src_subbmp = { NULL, NULL };
        ALLEGRO_BITMAP[] dst_subbmp = { NULL, NULL };
        ALLEGRO_EVENT @event = new ALLEGRO_EVENT();
        bool mouse_down;
        bool recreate_subbitmaps;
        bool redraw;
        bool use_memory;
        string image_filename = null;

        if (!al_init())
        {
            return 1;
        }
        al_init_primitives_addon();
        al_init_image_addon();

        open_log();

        al_set_new_display_flags(ALLEGRO_GENERATE_EXPOSE_EVENTS);
        src_display = al_create_display(SRC_WIDTH, SRC_HEIGHT);
        if (src_display == IntPtr.Zero)
        {
            abort_example("Error creating display\n");
            return 1;
        }
        al_set_window_title(src_display, "Source");

        dst_display = al_create_display(DST_WIDTH, DST_HEIGHT);
        if (dst_display == IntPtr.Zero)
        {
            abort_example("Error creating display\n");
            return 1;
        }
        al_set_window_title(dst_display, "Destination");

        {
            int i;
            for (i = 1; i < argv.Length; ++i)
            {
                if (image_filename == null)
                    image_filename = argv[i];
                else
                    Console.Write("Unknown argument: %s\n", argv[i]);
            }

            if (image_filename == null)
            {
                image_filename = "data/mysha.pcx";
            }
        }

        src_bmp = al_load_bitmap(image_filename);
        if (src_bmp == IntPtr.Zero)
        {
            abort_example("Could not load image file\n");
            return 1;
        }

        src_x2 = src_x1 + al_get_bitmap_width(src_bmp);
        src_y2 = src_y1 + al_get_bitmap_height(src_bmp);

        al_install_keyboard();
        al_install_mouse();

        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(src_display));
        al_register_event_source(queue, al_get_display_event_source(dst_display));

        mouse_down = false;
        recreate_subbitmaps = true;
        redraw = true;
        use_memory = false;

        log_printf("Highlight sub-bitmap regions with left mouse button.\n");
        log_printf("Press 'm' to toggle memory bitmaps.\n");
        log_printf("Press '1' to perform plain blits.\n");
        log_printf("Press 's' to perform scaled blits.\n");
        log_printf("Press 'h' to flip horizontally.\n");
        log_printf("Press 'v' to flip vertically.\n");

        while (true)
        {
            if (recreate_subbitmaps)
            {
                int l, r, t, b, sw, sh;

                al_destroy_bitmap(src_subbmp[0]);
                al_destroy_bitmap(dst_subbmp[0]);
                al_destroy_bitmap(src_subbmp[1]);
                al_destroy_bitmap(dst_subbmp[1]);

                l = MIN(src_x1, src_x2);
                r = MAX(src_x1, src_x2);
                t = MIN(src_y1, src_y2);
                b = MAX(src_y1, src_y2);

                l -= SRC_X;
                t -= SRC_Y;
                r -= SRC_X;
                b -= SRC_Y;

                src_subbmp[0] = al_create_sub_bitmap(src_bmp, l, t, r - l + 1,
                   b - t + 1);
                sw = al_get_bitmap_width(src_subbmp[0]);
                sh = al_get_bitmap_height(src_subbmp[0]);
                src_subbmp[1] = al_create_sub_bitmap(src_subbmp[0], 2, 2,
                   sw - 4, sh - 4);

                l = MIN(dst_x1, dst_x2);
                r = MAX(dst_x1, dst_x2);
                t = MIN(dst_y1, dst_y2);
                b = MAX(dst_y1, dst_y2);

                al_set_target_backbuffer(dst_display);
                dst_subbmp[0] = al_create_sub_bitmap(al_get_backbuffer(dst_display),
                   l, t, r - l + 1, b - t + 1);
                dst_subbmp[1] = al_create_sub_bitmap(dst_subbmp[0],
                   2, 2, r - l - 3, b - t - 3);

                recreate_subbitmaps = false;
            }

            if (redraw && al_is_event_queue_empty(queue))
            {
                al_set_target_backbuffer(dst_display);
                al_clear_to_color(al_map_rgb(0, 0, 0));

                al_set_target_bitmap(dst_subbmp[1]);
                switch (mode)
                {
                    case Mode.PLAIN_BLIT:
                        {
                            al_draw_bitmap(src_subbmp[1], 0, 0, draw_flags);
                            break;
                        }
                    case Mode.SCALED_BLIT:
                        {
                            al_draw_scaled_bitmap(src_subbmp[1],
                               0, 0, al_get_bitmap_width(src_subbmp[1]),
                               al_get_bitmap_height(src_subbmp[1]),
                               0, 0, al_get_bitmap_width(dst_subbmp[1]),
                               al_get_bitmap_height(dst_subbmp[1]),
                               draw_flags);
                            break;
                        }
                }

                {
                    /* pixel center is at 0.5/0.5 */
                    float x = dst_x1 + 0.5f;
                    float y = dst_y1 + 0.5f;
                    float x_ = dst_x2 + 0.5f;
                    float y_ = dst_y2 + 0.5f;
                    SWAP_GREATER(ref x, ref x_);
                    SWAP_GREATER(ref y, ref y_);
                    al_set_target_backbuffer(dst_display);
                    al_draw_rectangle(x, y, x_, y_,
                       al_map_rgb(0, 255, 255), 0);
                    al_draw_rectangle(x + 2, y + 2, x_ - 2, y_ - 2,
                       al_map_rgb(255, 255, 0), 0);
                    al_flip_display();
                }

                {
                    /* pixel center is at 0.5/0.5 */
                    float x = src_x1 + 0.5f;
                    float y = src_y1 + 0.5f;
                    float x_ = src_x2 + 0.5f;
                    float y_ = src_y2 + 0.5f;
                    SWAP_GREATER(ref x, ref x_);
                    SWAP_GREATER(ref y, ref y_);
                    al_set_target_backbuffer(src_display);
                    al_clear_to_color(al_map_rgb(0, 0, 0));
                    al_draw_bitmap(src_bmp, SRC_X, SRC_Y, 0);
                    al_draw_rectangle(x, y, x_, y_,
                       al_map_rgb(0, 255, 255), 0);
                    al_draw_rectangle(x + 2, y + 2, x_ - 2, y_ - 2,
                       al_map_rgb(255, 255, 0), 0);
                    al_flip_display();
                }

                redraw = false;
            }

            al_wait_for_event(queue, ref @event);
            if (@event.type == ALLEGRO_EVENT_DISPLAY_CLOSE)
            {
                break;
            }
            if (@event.type == ALLEGRO_EVENT_KEY_CHAR)
            {
                if (@event.keyboard.keycode == ALLEGRO_KEY_ESCAPE)
                {
                    break;
                }
                if (@event.keyboard.unichar == '1')
                {
                    mode = Mode.PLAIN_BLIT;
                    redraw = true;
                }
                else if (@event.keyboard.unichar == 's')
                {
                    mode = Mode.SCALED_BLIT;
                    redraw = true;
                }
                else if (@event.keyboard.unichar == 'h')
                {
                    draw_flags ^= ALLEGRO_FLIP_HORIZONTAL;
                    redraw = true;
                }
                else if (@event.keyboard.unichar == 'v')
                {
                    draw_flags ^= ALLEGRO_FLIP_VERTICAL;
                    redraw = true;
                }
                else if (@event.keyboard.unichar == 'm')
                {
                    ALLEGRO_BITMAP temp = src_bmp;
                    use_memory = !use_memory;
                    log_printf("Using a %s bitmap.\n", use_memory ? "memory" : "video");
                    al_set_new_bitmap_flags(use_memory ?
                       ALLEGRO_MEMORY_BITMAP : ALLEGRO_VIDEO_BITMAP);
                    src_bmp = al_clone_bitmap(temp);
                    al_destroy_bitmap(temp);
                    redraw = true;
                    recreate_subbitmaps = true;
                }
            }
            else if (@event.type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN &&
                  @event.mouse.button == 1)
            {
                if (@event.mouse.display == src_display)
                {
                    src_x1 = src_x2 = @event.mouse.x;
                    src_y1 = src_y2 = @event.mouse.y;
                }
                else if (@event.mouse.display == dst_display)
                {
                    dst_x1 = dst_x2 = @event.mouse.x;
                    dst_y1 = dst_y2 = @event.mouse.y;
                }
                mouse_down = true;
                redraw = true;
            }
            else if (@event.type == ALLEGRO_EVENT_MOUSE_AXES)
            {
                if (mouse_down)
                {
                    if (@event.mouse.display == src_display)
                    {
                        src_x2 = @event.mouse.x;
                        src_y2 = @event.mouse.y;
                    }
                    else if (@event.mouse.display == dst_display)
                    {
                        dst_x2 = @event.mouse.x;
                        dst_y2 = @event.mouse.y;
                    }
                    redraw = true;
                }
            }
            else if (@event.type == ALLEGRO_EVENT_MOUSE_BUTTON_UP &&
                  @event.mouse.button == 1)
            {
                mouse_down = false;
                recreate_subbitmaps = true;
                redraw = true;
            }
            else if (@event.type == ALLEGRO_EVENT_DISPLAY_EXPOSE)
            {
                redraw = true;
            }
        }

        al_destroy_event_queue(queue);

        close_log(false);
        return 0;
    }
}