import "raylib";
import libc "libc";
import "std_types";

WinX  := 1280;
WinY  := 720;
Mode  := 0;
RectX :: 16;
RectY :: 16;
Dt: float;

MouseX:= 0;
MouseY:= 0;
MouseP: Vector2 = {0, 0};

MouseSelecting := false;
MouseSelectionPivot: Vector2;
MouseSelectionBox: Rectangle;
MouseSelectedActors: ArrayOfActors;

AnimationSetTiles: ArrayOfAnimationSetTiles;

AnimationSetTile :: struct {
    set: bool;
    p:   V2I;
    t:   float;
}

ArrayOfAnimationSetTiles :: struct {
    data: *AnimationSetTile;
    len:   int;
    cap:   int;
}

main :: proc(): int {
    InitMap();
    InitWindow(WinX, WinY, "pathfinding visualizer");
    SetTargetFPS(60);

    orange  := ORANGE;
    orange.a = 255/2;
    brown  := BROWN;
    brown.a = 255/2;
    dark_green  := DARKGREEN;
    dark_green.a = 255/2;
    blue  := BLUE;
    blue.a = 255/2;
    green  := GREEN;
    green.a = 255/2;
    red := RED;
    red.a = 255/2;

    actor_color         := dark_green;
    past_actor_color    := blue;
    target_color        := red;
    selection_box_color := green;
    selected_color      := selection_box_color;

    for !WindowShouldClose() {
        WinX   = GetScreenHeight();
        WinY   = GetScreenWidth();
        MouseX = GetMouseX();
        MouseY = GetMouseY();
        MouseP = GetMousePosition();
        Dt     = GetFrameTime();
        @unused map := &CurrentMap;

        MouseSelecting = false;
        if IsMouseButtonDown(MOUSE_BUTTON_LEFT) {
            MouseSelecting = true;
            if IsMouseButtonPressed(MOUSE_BUTTON_LEFT) {
                MouseSelectionPivot = MouseP;
            }

            MouseSelectionBox = {
                MouseSelectionPivot.x,
                MouseSelectionPivot.y,
                MouseP.x - MouseSelectionPivot.x,
                MouseP.y - MouseSelectionPivot.y,
            };

            if MouseSelectionBox.width < 0 {
                MouseSelectionBox.x    += MouseSelectionBox.width;
                MouseSelectionBox.width = -MouseSelectionBox.width;
            }
            if MouseSelectionBox.height < 0 {
                MouseSelectionBox.y     += MouseSelectionBox.height;
                MouseSelectionBox.height = -MouseSelectionBox.height;
            }
        }

        if IsKeyPressed(KEY_F1) {
            Mode = 0;
        }

        if IsKeyPressed(KEY_F2) {
            Mode = 1;
        }

        if IsKeyPressed(KEY_F3) {
            for i := 0; i < map.actors.len; i += 1 {
                it := &map.actors.data[i];
                MoveTowardsTarget(it);
            }
        }
        PathFindUpdate(map);

        if IsKeyPressed(KEY_F4) {
            RandomizeActors();
        }

        BeginDrawing();
        ClearBackground(RAYWHITE);

        map_rectangle: Rectangle = {0, 0, :float(map.x) * RectX, :float(map.y) * RectY};
        DrawRectangleRec(map_rectangle, LIGHTGRAY);

        for x := 0; x < map.x; x += 1 {
            for y := 0; y < map.y; y += 1 {
                it := map.data[x + y*map.x];
                r : Rectangle = {:float(x) * RectX, :float(y) * RectY, RectX, RectY};
                r2: Rectangle = {r.x + 1, r.y + 1, r.width - 2, r.height - 2};

                colliding := CheckCollisionPointRec(MouseP, r);
                color := RAYWHITE;
                if it == 1 { color = GRAY; }

                if Mode == 0 {
                    if colliding && IsMouseButtonDown(MOUSE_BUTTON_LEFT) {
                        AddAnimationSetTile(&AnimationSetTiles, {true, {x,y}});
                    }
                    if colliding && IsMouseButtonDown(MOUSE_BUTTON_RIGHT) {
                        AddAnimationSetTile(&AnimationSetTiles, {false, {x,y}});
                    }
                    if colliding {
                        color.a = 100;
                    }
                }

                DrawRectangleRec(r2, color);
            }
        }

        for tile_i := 0; tile_i < AnimationSetTiles.len; tile_i += 1 {
            tile_it := &AnimationSetTiles.data[tile_i];
            remove  := false;

            t := tile_it.t;
            if tile_it.set == false {
                t = 1 - t;
            }

            x := :float(tile_it.p.x) * RectX + 1;
            y := :float(tile_it.p.y) * RectY + 1;

            w: float = RectX - 2;
            h: float = RectY - 2;
            wt := w * t;
            ht := h * t;
            wd := w - wt;
            hd := h - ht;

            r: Rectangle = {x + wd/2, y + hd/2, wt, ht};
            DrawRectangleRec(r, GRAY);

            if tile_it.t > 1 {
                map_tile := &map.data[tile_it.p.x + tile_it.p.y*map.x];
                if tile_it.set  {*map_tile |=  TILE_BLOCKER;}
                else            {*map_tile &= ~TILE_BLOCKER;}

                remove = true;
            }

            tile_it.t += Dt*8;
            if remove {
                UnorderedRemoveAnimationSetTile(&AnimationSetTiles, tile_it);
                tile_i -= 1;
            }
        }

        for actor_i := 0; actor_i < map.actors.len; actor_i += 1 {
            actor_it := &map.actors.data[actor_i];
            target_r := Rect(actor_it.target_p);

            main_p := Circle(actor_it.p);
            DrawCircleV(main_p, RectX/2, actor_color);
            DrawRectangleRec(target_r, target_color);

            smaller_the_further: float;
            for tile_i := actor_it.tiles_visited.len - 1; tile_i >= 0; tile_i -= 1 {
                tile_it := &actor_it.tiles_visited.data[tile_i];
                p := Circle({tile_it.x, tile_it.y});
                DrawCircleV(p, RectX/2 - smaller_the_further, past_actor_color);
                smaller_the_further += 0.5;
            }

            for path_i := 0; path_i < actor_it.open_paths.len; path_i += 1 {
                path_it := &actor_it.open_paths.data[path_i];
                path_r  := Rect(path_it.p);
                DrawRectangleRec(path_r, orange);
                s := TextFormat("%d", :int(libc.sqrtf(:float(path_it.value_to_sort_by))));
                DrawText(s, :int(path_r.x), :int(path_r.y), 1, RAYWHITE);
            }

            for path_i := 0; path_i < actor_it.close_paths.len; path_i += 1 {
                path_it := &actor_it.close_paths.data[path_i];
                path_r  := Rect(path_it.p);
                DrawRectangleRec(path_r, brown);
            }

            for path_i := 0; path_i < actor_it.history.len; path_i += 1 {
                path_it := &actor_it.history.data[path_i];

                p0 := Circle(path_it.came_from);
                p1 := Circle(path_it.p);

                DrawLineEx(p0, p1, 5, LIGHTGRAY);
                DrawCircleV(p0, 4, LIGHTGRAY);
                DrawCircleV(p1, 4, LIGHTGRAY);
            }
        }

        if Mode == 1 {
            for actor_i := 0; actor_i < MouseSelectedActors.len; actor_i += 1 {
                actor_it := &MouseSelectedActors.data[actor_i];
                actor_box := Rect(actor_it.p);
                DrawRectangleRec(actor_box, selected_color);

                if IsMouseButtonPressed(MOUSE_BUTTON_RIGHT) {
                    p := ScreenToMap(MouseP);
                    SetTargetP(actor_it, p);
                }
            }

            if MouseSelecting {
                MouseSelectedActors.len = 0;
                for actor_i := 0; actor_i < MouseSelectedActors.len; actor_i += 1 {
                    actor_it := &MouseSelectedActors.data[actor_i];
                    actor_box := Rect(actor_it.p);

                    if CheckCollisionRecs(actor_box, MouseSelectionBox) {
                        AddActorToArray(&MouseSelectedActors, *actor_it);
                    }
                }
                DrawRectangleRec(MouseSelectionBox, selection_box_color);
            }
        }

        text_size := 24;
        text_p    := 4;
        text_y    := text_size * 2;

        DrawText("F4 :: Randomize actors", text_p, text_y, text_size, GRAY);
        text_y -= text_size;
        DrawText("F3 :: Simulate actors", text_p, text_y, text_size, GRAY);
        text_y -= text_size;
        text: *char = "Mode(F1) :: Block placing";
        if Mode == 1 { text = "Mode(F2) :: Actor placing"; }
        DrawText(text, text_p, text_y, text_size, GRAY);
        text_y -= text_size;

        EndDrawing();
    }

    return 0;
}