#include "menu.h"
#define S(text) \
    strcpy(menu->items [menu->pos] [menu->n [menu->pos]++], text);
#define T \
    menu->pos++; \
    menu->n [menu->pos] = 0;
static int category(BlockType * bt);
static char const* category_name(int c);
static void menu_items(Menu * menu);
Menu* menu_new(void) {
    Menu * menu;
    land_alloc(menu);
    return menu;
}
#define categories_count 8
static int category(BlockType * bt) {
    if (land_starts_with(bt->name, "BlockBottom") || land_starts_with(bt->name, "BlockSmall") || land_starts_with(bt->name, "Ramp") || land_starts_with(bt->name, "block-")) {
        return 0;
    }
    if (land_starts_with(bt->name, "Block") || land_starts_with(bt->name, "Invisible") || land_starts_with(bt->name, "Window")) {
        return 1;
    }
    if (block_type_flower(bt)) {
        return 2;
    }
    if (land_starts_with(bt->name, "PyramidTree")) {
        return 3;
    }
    if (land_starts_with(bt->name, "Lever") || land_starts_with(bt->name, "Vent") || land_starts_with(bt->name, "Plate") || land_starts_with(bt->name, "Platform") || land_starts_with(bt->name, "Waypoint") || land_starts_with(bt->name, "Exit") || land_starts_with(bt->name, "Conveyor")) {
        return 4;
    }
    if (bt->dynamic) {
        return 5;
    }
    if (land_starts_with(bt->name, "Tree") || land_ends_with(bt->name, "Tree")) {
        return 6;
    }
    return 7;
}
static char const* category_name(int c) {
    if (c == 0) {
        return "Floor";
    }
    if (c == 1) {
        return "Wall";
    }
    if (c == 2) {
        return "Item";
    }
    if (c == 3) {
        return "Monster";
    }
    if (c == 4) {
        return "Device";
    }
    if (c == 5) {
        return "Moving";
    }
    if (c == 6) {
        return "Plant";
    }
    if (c == 7) {
        return "Decoration";
    }
    return "";
}
static void menu_items(Menu * menu) {
    Application * a = app();
    menu->pos = 0;
    menu->n [0] = 0;
    S("Mode");
    S("File");
    S("View");
    S("Level");
    S("Object");
    T;
    S(a->editor ? "Play" : "Edit");
    S("Godmode");
    S("Exit");
    T;
    S("Save");
    S("Load");
    S("Clear");
    S("Boardwalk");
    S("Crosswalk");
    T;
    S("Bounds");
    S("Mask");
    S("Info");
    T;
    S("Overview");
    S("Intro");
    S("Title");
    S("Hint");
    S("Shift X+");
    S("Shift X-");
    S("Shift Y+");
    S("Shift Y-");
    S("Shift Z+");
    S("Shift Z-");
    T;
    S("Insert");
    S("Type");
    S("Frame");
    S("Align");
    S("Delete");
    T;
    for (int i = 0; i < categories_count; i += 1) {
        S(category_name(i));
    }
    for (int i = 0; i < categories_count; i += 1) {
        T;
        {
            LandArrayIterator __iter0__ = LandArrayIterator_first(block_types);
            for (BlockType * bt = LandArrayIterator_item(block_types, &__iter0__); LandArrayIterator_next(block_types, &__iter0__); bt = LandArrayIterator_item(block_types, &__iter0__)) {
                if (category(bt) == i) {
                    S(bt->name);
                }
            }
        }
    }
    T;
    S("0");
    S("1");
    menu->sub_frame = menu->pos;
}
void menu_toggle(void) {
    if (game->menu_on) {
        game->menu_on = 0;
    }
    else {
        game->menu_on = 1;
        Menu * menu = game->menu;
        menu_items(menu);
        menu->hilite [0] = - 1;
        menu->menu [0] = 0;
        menu->menu [1] = - 1;
        menu->menu [2] = - 1;
    }
}
void menu_draw(Menu * menu) {
    Application * a = app();
    float w = land_display_width();
    land_push_transform();
    land_scale(w / 960.0, w / 960.0);
    float mw = 120;
    float mih = 30;
    float border = 40;
    for (int mi = 0; mi < 3; mi += 1) {
        int m = menu->menu [mi];
        if (m == - 1) {
            break;
        }
        float x0 = 960 - (mw + border) * (1 + mi);
        float y0 = 160;
        land_font_set(a->medium);
        int n = menu->n [m];
        land_premul(1, 1, 1, 0.8);
        land_filled_rectangle(x0 - border, y0 - border, x0 + mw + border, y0 + n * mih + border);
        land_color(1, 1, 0, 1);
        int t = 4;
        land_thickness(t * 2);
        land_rectangle(x0 - border + t, y0 - border + t, x0 + mw + border - t, y0 + n * mih + border - t);
        land_thickness(1);
        for (int i = 0; i < n; i += 1) {
            char * text = menu->items [m] [i];
            float x = x0;
            float y = y0 + i * mih;
            if (menu->hilite [mi] == i) {
                land_color(1, 1, 0.5, 1);
                land_filled_rectangle(x, y, x + mw, y + mih);
            }
            land_text_pos(x, y);
            land_color(0, 0, 0, 1);
            land_print("%s", text);
        }
    }
    land_pop_transform();
}
void menu_key(int k, bool shift) {
    Application * a = app();
    if (finding_input) {
        if (land_key_pressed(LandKeyEscape) || land_key_pressed(LandKeyBack) || controls.pressed [ControlMenu]) {
            finding_input = 0;
            return ;
        }
        if (! land_keybuffer_empty()) {
            controls.c [finding_control] [0] = k;
            controls.c [finding_control] [1] = 0;
            finding_input = 0;
        }
        return ;
    }
    if (k == LandKeyFunction + 2) {
        if (game->pristine) {
            save_level(1, 0);
        }
    }
    else if (k == LandKeyFunction + 3) {
        load_level(1, 0);
        a->overview = 0;
        viewport_update(game->viewport, land_display_width(), land_display_height());
        a->editor = 1;
    }
    else if (k == LandKeyFunction + 4) {
        blocks_reset(game->blocks);
        game->skunk = NULL;
    }
    else if (k == LandKeyFunction + 5) {
        debug_no_mask = ! debug_no_mask;
    }
    else if (k == LandKeyFunction + 6) {
        debug_bounding_boxes++;
        debug_bounding_boxes %= 2;
    }
    else if (k == LandKeyFunction + 7) {
        a->editor = ! a->editor;
    }
    else if (k == LandKeyFunction + 8) {
        if (a->overview) {
            a->overview = 0;
            game->level = game->overview->selected;
            menu_key(LandKeyFunction + 3, 0);
        }
        else {
            overview_update(game->overview);
        }
    }
    else if (k == ' ') {
        ;
    }
    else if (k == LandKeyEnter) {
        store_player_pos();
        a->editor = ! a->editor;
        a->overview = 0;
    }
    else if (k == 'q' || k == 'e' || k == 'w' || k == 's') {
        if (k == 'q' || k == 'e' || ! editor->picked) {
            int gox = 0, goz = 0;
            if (k == 'q') {
                gox--;
            }
            if (k == 'e') {
                gox++;
            }
            if (k == 'w') {
                goz--;
            }
            if (k == 's') {
                goz++;
            }
            game->level = game_neighboring_level(game->level, gox, goz);
            load_level(1, 0);
            a->editor = 1;
        }
    }
    else if (k == 'i') {
        Block * p = editor->picked;
        if (p) {
            BlockType * pt = p->block_type;
            print("F%d X%.1f Y%.1f Z%.1f %3.1f/%3.1f/%3.1f %s", p->frame, p->x, p->y, p->z, p->x / 24 + 22, p->y / 24 + 4, p->z / 24 + 22, pt->name);
        }
    }
    else if (k == 't') {
        a->text_input = 1;
        a->cursor = 0;
    }
    else if (k == 'h') {
        a->text_input = 2;
        a->cursor = 0;
    }
    else if (k == 'g') {
        a->godmode = ! a->godmode;
    }
    if (! editor->picked) {
        if (k == 'x') {
            blocks_shift(game->blocks, shift ? 24 : - 24, 0, 0);
        }
        else if (k == 'y') {
            blocks_shift(game->blocks, 0, shift ? 24 : - 24, 0);
        }
        else if (k == 'z') {
            blocks_shift(game->blocks, 0, 0, shift ? 24 : - 24);
        }
    }
    double s = 24;
    double s2 = s * 2;
    if (shift) {
        s2 = s;
    }
    if (k == LandKeyInsert) {
        Block * l = editor->picked;
        if (l) {
            editor->picked = block_new(game->blocks, l->x, l->y, l->z, l->block_type);
        }
        else {
            editor->picked = block_new(game->blocks, - 24, 0, - 24, Data_BlockWood);
        }
        block_add(editor->picked);
    }
    Block * p = editor->picked;
    if (! p) {
        return ;
    }
    if (k == LandKeyLeft) {
        p->x -= s2;
        game_recalc();
    }
    else if (k == LandKeyRight) {
        p->x += s2;
        game_recalc();
    }
    else if (k == LandKeyUp) {
        p->z -= s2;
        game_recalc();
    }
    else if (k == LandKeyDown) {
        p->z += s2;
        game_recalc();
    }
    else if (k == 'w') {
        p->y += s2;
        game_recalc();
    }
    else if (k == 's') {
        p->y -= s2;
        game_recalc();
    }
    else if (k == 'x') {
        if (shift) {
            p->y += p->ys;
        }
        else {
            p->y -= p->ys;
        }
    }
    else if (k == 'c') {
        if (shift) {
            p->x = floor(p->x / s) * s;
            p->y = floor(p->y / s) * s;
            p->z = floor(p->z / s) * s;
            p->x += (s - p->xs) / 2;
            p->z += (s - p->zs) / 2;
        }
        else {
            p->x = floor(p->x / s + 0.1) * s;
            p->y = floor(p->y / s + 0.1) * s;
            p->z = floor(p->z / s + 0.1) * s;
        }
    }
    else if (k == 'a') {
        editor->picked = p = block_change_type(p, - 1);
    }
    else if (k == 'd') {
        editor->picked = p = block_change_type(p, 1);
    }
    else if (k == 'f') {
        p->frame++;
        if (p->frame >= land_array_count(p->block_type->bitmaps)) {
            p->frame = 0;
        }
    }
    else if (k == LandKeyDelete) {
        block_del(p);
        editor->picked = NULL;
    }
}
bool menu_tick(Menu * menu, float mx, float my, float click) {
    Application * a = app();
    float w = land_display_width();
    float mw = 120 * w / 960;
    float mih = 30 * w / 960;
    float border = 40 * w / 960;
    bool out = 1;
    char * text = NULL;
    int selected = - 1;
    int mi;
    for (mi = 0; mi < 3; mi += 1) {
        float x0 = w - (mw + border) * (1 + mi);
        float y0 = 160 * w / 960;
        if (menu->menu [mi] == - 1) {
            break;
        }
        int n = menu->n [menu->menu [mi]];
        menu->hilite [mi] = - 1;
        if (mx < x0 - border) {
            continue;
        }
        if (mx > x0 + mw + border) {
            continue;
        }
        if (my < y0 - border) {
            continue;
        }
        if (my > y0 + n * mih + border) {
            continue;
        }
        out = 0;
        if (mx < x0 || mx > x0 + mw) {
            continue;
        }
        selected = floor((my - y0) / mih);
        if (selected < 0 || selected >= n) {
            continue;
        }
        text = menu->items [menu->menu [mi]] [selected];
        break;
    }
    if (out) {
        return 0;
    }
    if (! text) {
        return 1;
    }
    if (click) {
        if (menu->menu [mi] > 0) {
            game->menu_on = 0;
            menu->menu [0] = 0;
            menu->menu [1] = - 1;
        }
        if (land_equals(text, "Mode")) {
            menu->menu [mi] = 1;
        }
        if (land_equals(text, "File")) {
            menu->menu [mi] = 2;
        }
        if (land_equals(text, "View")) {
            menu->menu [mi] = 3;
        }
        if (land_equals(text, "Level")) {
            menu->menu [mi] = 4;
        }
        if (land_equals(text, "Object")) {
            menu->menu [mi] = 5;
        }
        if (land_equals(text, "Exit")) {
            a->editor = 0;
            main_switch_to_title(0);
        }
        if (land_equals(text, "Play")) {
            a->editor = 0;
        }
        if (land_equals(text, "Edit")) {
            a->editor = 1;
        }
        ON("Godmode", 'g');
        ON("Save", LandKeyFunction + 2);
        ON("Load", LandKeyFunction + 3);
        ON("Clear", LandKeyFunction + 4);
        ON("Bounds", LandKeyFunction + 6);
        ON("Mask", LandKeyFunction + 5);
        ON("Info", 'i');
        ON("Overview", LandKeyFunction + 8);
        ON("Intro", LandKeyFunction + 10);
        ON("Title", 't');
        ON("Hint", 'h');
        ON_SHIFT("Shift X+", 'x');
        ON("Shift X-", 'x');
        ON_SHIFT("Shift Y+", 'y');
        ON("Shift Y-", 'y');
        ON_SHIFT("Shift Z+", 'z');
        ON("Shift Z-", 'z');
        ON("Delete", LandKeyDelete);
        if (land_equals(text, "Frame")) {
            menu->menu [0] = menu->sub_frame;
            menu->menu [1] = - 1;
            game->menu_on = 1;
            Block * p = editor->picked;
            if (p) {
                int n = land_array_count(p->block_type->bitmaps);
                if (n > 10) {
                    n = 10;
                }
                for (int i = 0; i < n; i += 1) {
                    sprintf(menu->items [menu->sub_frame] [i], "Frame %d", 1 + i);
                }
                menu->n [menu->sub_frame] = n;
            }
        }
        if (land_equals(text, "Type")) {
            menu->menu [mi] = 6;
            game->menu_on = 1;
        }
        ON("Align", 'c');
        ON("Insert", LandKeyInsert);
        if (land_equals(text, "Boardwalk")) {
            for (int i = 0; i < 12; i += 1) {
                int x = - 24 * 21 + i * 24 * 4;
                BlockType * bt = Data_BlockWood;
                if (i == 0) {
                    bt = Data_BlockExit;
                    x += 24 * 2;
                }
                if (i == 11) {
                    bt = Data_BlockExitR;
                }
                Block * b = block_new(game->blocks, x, 0, - 24, bt);
                block_add_if_no_overlap(b);
            }
        }
        if (land_equals(text, "Crosswalk")) {
            for (int i = 0; i < 12; i += 1) {
                int z = - 24 * 21 + i * 24 * 4;
                BlockType * bt = Data_BlockWood2;
                if (i == 0) {
                    bt = Data_BlockExitU;
                    z += 24 * 2;
                }
                if (i == 11) {
                    bt = Data_BlockExitD;
                }
                Block * b = block_new(game->blocks, - 24, 0, z, bt);
                block_add_if_no_overlap(b);
            }
        }
        if (land_starts_with(text, "Frame ")) {
            Block * p = editor->picked;
            if (p) {
                p->frame = selected;
                if (p->frame >= land_array_count(p->block_type->bitmaps)) {
                    p->frame = 0;
                }
            }
        }
        for (int c = 0; c < categories_count; c += 1) {
            if (land_equals(text, category_name(c))) {
                menu->menu [0] = 6;
                menu->menu [1] = 7 + c;
                game->menu_on = 1;
            }
        }
    }
    else {
        if (mi == 1) {
            if (editor->picked) {
                editor->picked = block_change_type_to(editor->picked, text);
            }
        }
        menu->hilite [mi] = selected;
    }
    return 1;
}
