#include "main.h"
static void cheat(char unichar);
static void _redraw(void);
void main_switch_to_game(void) {
    Application * a = app();
    a->title = 0;
    if (! game->state) {
        a->load_after_redraw = 1;
    }
}
void main_switch_to_title(int com) {
    Application * a = app();
    a->title = 1;
    a->overview = 0;
    title_com(com);
}
void sound(LandSound * s, float vol) {
    Application * a = app();
    land_sound_play(s, vol * a->sound / 6.0, 0, 1);
}
void add_time(void) {
    Application * a = app();
    a->frame_times [a->ftpos] = land_get_time();
    a->ftpos += 1;
    if (a->ftpos >= a->FPS) {
        a->ftpos = 0;
    }
}
void get_fps(double * average, double * minmax) {
    Application * a = app();
    int prev = a->FPS - 1;
    double min_dt = 1;
    double max_dt = 1 / 1000000.0;
    double av = 0;
    for (int i = 0; i < a->FPS; i += 1) {
        if (i != a->ftpos) {
            double dt = a->frame_times [i] - a->frame_times [prev];
            if (dt < min_dt && dt > 0) {
                min_dt = dt;
            }
            if (dt > max_dt) {
                max_dt = dt;
            }
            av += dt;
        }
        prev = i;
    }
    av /= (double) a->FPS - 1;
    * average = ceil(1 / av);
    double d = 1 / min_dt - 1 / max_dt;
    * minmax = floor(d / 2);
}
void redraw(void) {
    Application * a = app();
    if (a->load_after_redraw) {
        if (! a->overview) {
            data_loading_screen();
        }
        if (a->load_after_redraw == 1) {
            a->load_after_redraw = 2;
        }
        else if (a->load_after_redraw == 2) {
            // wait for logic code to advance
            ;
        }
        if (a->load_after_redraw > 2) {
            a->load_after_redraw++;
            double t = land_get_time();
            while (1) {
                if (! blocks_preload(game->blocks)) {
                    a->load_after_redraw = 0;
                    if (a->overview) {
                        overview_render_next(game->overview);
                    }
                    break;
                }
                if (land_get_time() > t + 0.01) {
                    break;
                }
            }
        }
        if (! a->overview) {
            return ;
        }
    }
    float w = land_display_width();
    float h = land_display_height();
    //float fh = land_font_height(a->font)
    if (a->title) {
        title_render();
    }
    else {
        render(game, w, h);
    }
    if (a->show_fps) {
        double f1, f2;
        get_fps(& f1, & f2);
        land_text_pos(w, 0);
        land_font_set(a->font);
        land_color(a->text.r, a->text.g, a->text.b, a->text.a);
        land_print_right("FPS: %4d +- %-4d", (int) f1, (int) f2);
        land_print_right("%4d / sec", (int)(1.0 / a->direct_speed_measure));
    }
}
void reload_fonts(void) {
    Application * a = app();
    float w = land_display_width();
    //float h = land_display_height()
    double s = w / 960;
    if (a->font) {
        land_font_destroy(a->font);
    }
    if (a->medium) {
        land_font_destroy(a->medium);
    }
    if (a->big) {
        land_font_destroy(a->big);
    }
    a->font = land_font_load(FONT, 10 * s);
    land_font_scale(a->font, 1.0 / s);
    a->medium = land_font_load(FONT, 24 * s);
    land_font_scale(a->medium, 1.0 / s);
    a->big = land_font_load(FONT, 60 * s);
    land_font_scale(a->big, 1.0 / s);
    land_font_set(a->medium);
    land_text_get_width("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
}
void init(void) {
    Application * a = app();
    land_find_data_prefix("data/");
    a->title = 1;
    a->FPS = 60;
    a->font = NULL;
    a->ftpos = 0;
    a->direct_speed_measure = a->FPS;
    a->show_fps = 0;
    land_display_title(TITLE);
    LandImage * icon = data_load_icon();
    if (! land_image_was_loaded(icon)) {
        print("icon missing");
        land_quit();
        return ;
    }
    land_display_icon(icon);
    land_image_destroy(icon);
    reload_fonts();
    a->up = 0;
    a->down = 0;
    a->left = 0;
    a->right = 0;
    a->jump = 0;
    a->text = (LandColor) {0, 0, 0, 1};
    config_controls_read();
    title_init();
    game_setup(land_display_width(), land_display_height());
    data_load();
    render_setup();
    a->show_fps = 0;
    for (int i = 0; i < 10; i += 1) {
        a->cheatpos [i] = 0;
    }
}
void done(void) {
    Application * a = app();
    game_del(game);
    if (a->font) {
        land_font_destroy(a->font);
    }
}
void update(void) {
    Application * a = app();
    if (land_was_resized()) {
        viewport_update(game->viewport, land_display_width(), land_display_height());
        a->resize_in_ticks = 10;
    }
    if (a->resize_in_ticks > 0) {
        a->resize_in_ticks--;
        if (a->resize_in_ticks == 0) {
            reload_fonts();
        }
    }
    if (a->load_after_redraw) {
        if (a->load_after_redraw == 2) {
            print("load after redraw");
            bool previous = 0;
            bool respawn = 0;
            if (game->skunk) {
                if (land_equals(game->state, "died")) {
                    respawn = 1;
                }
                previous = 1;
            }
            load_level(a->editor, a->find_entrance);
            if (a->find_entrance) {
                a->find_entrance = 0;
                if (respawn) {
                    if (game->elephant) {
                        game->elephant->x = game->enter_x2;
                        game->elephant->y = game->enter_y2;
                        game->elephant->z = game->enter_z2;
                        avoid_collision(game->elephant);
                    }
                    if (game->skunk) {
                        game->skunk->x = game->enter_x;
                        game->skunk->y = game->enter_y;
                        game->skunk->z = game->enter_z;
                        avoid_collision(game->skunk);
                    }
                }
                else if (previous) {
                    player_find_entrance();
                }
            }
            store_player_pos();
            a->load_after_redraw++;
        }
        return ;
    }
    config_check_controls(a);
    if (a->title) {
        title_tick();
    }
    else {
        game_tick(game);
    }
}
void store_player_pos(void) {
    if (game->skunk) {
        game->enter_x = game->skunk->x;
        game->enter_y = game->skunk->y;
        game->enter_z = game->skunk->z;
    }
    if (game->elephant) {
        game->enter_x2 = game->elephant->x;
        game->enter_y2 = game->elephant->y;
        game->enter_z2 = game->elephant->z;
    }
}
static void cheat(char unichar) {
    Application * a = app();
    char const * cheatcodes [] = {"iddqd", "idflower", "idkey"};
    for (int i = 0; i < 3; i += 1) {
        if (unichar == cheatcodes [i] [a->cheatpos [i]]) {
            a->cheatpos [i] += 1;
            if (a->cheatpos [i] == (int) strlen(cheatcodes [i])) {
                a->cheatpos [i] = 0;
                if (i == 0) {
                    a->godmode = ! a->godmode;
                }
                if (i == 1) {
                    for (int j = 1; j < 8; j += 1) {
                        game->flower [j] = 1;
                        game->test_tube [j] = 1;
                    }
                }
                if (i == 2) {
                    game->key = ! game->key;
                }
            }
        }
        else {
            a->cheatpos [i] = 0;
        }
    }
}
void main_tick(void) {
    Application * a = app();
    update();
    if (land_closebutton()) {
        save_level(0, 0);
        land_quit();
    }
    if (land_switched_out()) {
        save_level(0, 0);
    }
    if (land_was_halted()) {
        ;
    }
    if (! land_keybuffer_empty()) {
        int k, u;
        land_keybuffer_next(& k, & u);
        cheat(u);
        if (k == LandKeyEscape) {
            if (! a->title) {
                main_switch_to_title(0);
            }
        }
        else if (k == LandKeyFunction + 1) {
            a->show_fps = ! a->show_fps;
        }
        else {
            if (a->text_input) {
                if (u == '|') {
                    u = '\n';
                }
                if (u == 13) {
                    u = 0;
                }
                if (a->text_input == 1) {
                    game->title [a->cursor++] = u;
                }
                else if (a->text_input == 2) {
                    game->hint [a->cursor++] = u;
                }
                if (u == 0) {
                    a->text_input = 0;
                }
            }
            else if (! a->title) {
                if (a->editor) {
                    game_key(game, k);
                }
            }
        }
    }
}
//elif k == 'm':
//    land_stream_set_playing(render_music,
//        not land_stream_is_playing(render_music))
static void _redraw(void) {
    Application * a = app();
    double t = - land_get_time();
    add_time();
    redraw();
    t += land_get_time();
    a->direct_speed_measure = t;
}
int my_main(void) {
    Application * a;
    land_alloc(a);
    a->show_help = 1;
    platform_debug(1);
    land_init();
    int w0, h0;
    land_display_desktop_size(& w0, & h0);
    int w = (int)(w0 * 3 / 4);
    int h = (int)(w * 9 / 16);
    #ifdef ANDROID
    land_set_display_parameters(0, 0, LAND_FULLSCREEN | LAND_DEPTH | LAND_LANDSCAPE | LAND_FRAMELESS);
    #else
    land_set_display_parameters(w, h, LAND_DEPTH | LAND_RESIZE | LAND_OPENGL);
    #endif
    a->w = w;
    a->h = h;
    land_callbacks(init, main_tick, _redraw, done);
    land_mainloop();
    land_free(a);
    return 0;
}
#ifdef MACOS
int _al_mangled_main(int argc, char * (* argv));
#endif
land_use_main(my_main);
