define(["jquery", "./map_knowledge", "./dungeon_renderer", "./view_data",
        "./tileinfo-player", "./tileinfo-main", "./tileinfo-dngn", "./enums",
        "./player", "./options", "./util"],
function ($, map_knowledge, dungeon_renderer, view_data,
          tileinfo_player, main, dngn, enums, player, options, util) {
    "use strict";

    var minimap_colours;
    var overlay;
    var ctx, overlay_ctx;
    var cell_w, cell_h;
    var cell_x = 0, cell_y = 0;
    var display_x = 0, display_y = 0;
    var enabled = true;

    function vcolour_to_css_colour(colour)
    {
        return "rgba(" + colour.r + "," + colour.g + "," + colour.b + ","
               + (colour.a ? colour.a : 255) + ")";
    }

    function update_overlay()
    {
        // Update the minimap overlay
        var view = dungeon_renderer.view;
        overlay_ctx.clearRect(0, 0, overlay.width, overlay.height);
        overlay_ctx.strokeStyle =
            vcolour_to_css_colour(options.get("tile_window_col"));
        overlay_ctx.strokeRect(display_x + (view.x - cell_x) * cell_w + 0.5,
                               display_y + (view.y - cell_y) * cell_h + 0.5,
                               dungeon_renderer.cols * cell_w - 1,
                               dungeon_renderer.rows * cell_h - 1);
    }

    function fit_to(width)
    {
        var gxm = enums.gxm;
        var gym = enums.gym;
        var display = $("#minimap").css("display");
        $("#minimap, #minimap_overlay").show();

        var block = $("#minimap_block");
        var canvas = $("#minimap")[0];
        if (!canvas) return;

        block.width(width);
        canvas.width = width;
        cell_w = cell_h = Math.floor(width / gxm);
        if (options.get("tile_map_pixels") > 0)
            cell_w = cell_h = Math.min(cell_w, options.get("tile_map_pixels"));
        block.height(gym * cell_h);
        canvas.height = gym * cell_h;
        ctx = canvas.getContext("2d");

        overlay = $("#minimap_overlay")[0];
        overlay.width = canvas.width;
        overlay.height = canvas.height;
        overlay_ctx = overlay.getContext("2d");

        if (cell_x !== 0 || cell_y !== 0)
        {
            clear();
            center();
        }

        $("#minimap, #minimap_overlay").css("display", display);
        // suppress rclick menu (so we can rclick to view)
        $("#minimap")[0].oncontextmenu =  function() { return false; }
        overlay.oncontextmenu =  function() { return false; }
    }

    function clear()
    {
        ctx.fillStyle = "black";
        ctx.fillRect(0, 0,
                     $("#minimap").width(),
                     $("#minimap").height());
    }

    function center()
    {
        if (!enabled) return;

        stop_minimap_farview();

        var minimap = $("#minimap")[0];
        var bounds = map_knowledge.bounds();
        var mm_w = bounds.right - bounds.left;
        var mm_h = bounds.bottom - bounds.top;

        if (mm_w < 0 || mm_h < 0) return;

        var old_x = display_x - cell_x * cell_w;
        var old_y = display_y - cell_y * cell_h;

        cell_x = bounds.left;
        cell_y = bounds.top;
        display_x = Math.floor((minimap.width - cell_w * mm_w) / 2);
        display_y = Math.floor((minimap.height - cell_h * mm_h) / 2);

        var dx = display_x - cell_x * cell_w - old_x;
        var dy = display_y - cell_y * cell_h - old_y;

        ctx.drawImage(minimap, 0, 0, minimap.width, minimap.height,
                               dx, dy, minimap.width, minimap.height);

        ctx.fillStyle = "black";
        if (dx > 0)
            ctx.fillRect(0, 0, dx, minimap.height);
        if (dx < 0)
            ctx.fillRect(minimap.width + dx, 0, -dx, minimap.height);
        if (dy > 0)
            ctx.fillRect(0, 0, minimap.width, dy);
        if (dy < 0)
            ctx.fillRect(0, minimap.height + dy, minimap.width, -dy);

        update_overlay();
    }

    function set(cx, cy, colour)
    {
        if (!enabled || colour === undefined) return;

        var x = cx - cell_x;
        var y = cy - cell_y;
        ctx.fillStyle = colour;
        ctx.fillRect(display_x + x * cell_w,
                     display_y + y * cell_h,
                     cell_w, cell_h);
    }

    function init_options()
    {
        // This must match the order of map_feature in map-feature.h
        minimap_colours = [
            options.get("tile_unseen_col"),         // MF_UNSEEN
            options.get("tile_floor_col"),          // MF_FLOOR
            options.get("tile_wall_col"),           // MF_WALL
            options.get("tile_mapped_floor_col"),   // MF_MAP_FLOOR
            options.get("tile_mapped_wall_col"),    // MF_MAP_WALL
            options.get("tile_door_col"),           // MF_DOOR
            options.get("tile_item_col"),           // MF_ITEM
            options.get("tile_monster_col"),        // MF_MONS_FRIENDLY
            options.get("tile_monster_col"),        // MF_MONS_PEACEFUL
            options.get("tile_monster_col"),        // MF_MONS_NEUTRAL
            options.get("tile_monster_col"),        // MF_MONS_HOSTILE
            options.get("tile_plant_col"),          // MF_MONS_NO_EXP
            options.get("tile_upstairs_col"),       // MF_STAIR_UP
            options.get("tile_downstairs_col"),     // MF_STAIR_DOWN
            options.get("tile_branchstairs_col"),   // MF_STAIR_BRANCH
            options.get("tile_feature_col"),        // MF_FEATURE
            options.get("tile_water_col"),          // MF_WATER
            options.get("tile_lava_col"),           // MF_LAVA
            options.get("tile_trap_col"),           // MF_TRAP
            options.get("tile_excl_centre_col"),    // MF_EXCL_ROOT
            options.get("tile_excluded_col"),       // MF_EXCL
            options.get("tile_player_col"),         // MF_PLAYER
            options.get("tile_deep_water_col"),     // MF_DEEP_WATER
            options.get("tile_portal_col"),         // MF_PORTAL
            options.get("tile_transporter_col"),    // MF_TRANSPORTER
            options.get("tile_transporter_landing_col"), // MF_TRANSPORTER_LANDING
            options.get("tile_explore_horizon_col") // MF_EXPLORE_HORIZON
        ].map(vcolour_to_css_colour);
    }

    function update(x, y, cell)
    {
        cell = cell || map_knowledge.get(x, y);
        if (x == player.pos.x && y == player.pos.y)
            set(x, y, minimap_colours[enums.MF_PLAYER]);
        else
            set(x, y, minimap_colours[cell.mf || enums.MF_UNSEEN]);
    }

    // Minimap controls ------------------------------------------------------------
    function vgrdc(x, y)
    {
        dungeon_renderer.set_view_center(x, y);

        update_overlay();
    }

    function do_view_center_update(x, y)
    {
        // Update the viewpoint, unless the user is currently
        // right-clicking on the map
        if (farview_old_vc)
        {
            farview_old_vc.x = x;
            farview_old_vc.y = y;
        }
        else
        {
            vgrdc(x, y);
        }
    }

    var farview_old_vc;
    function minimap_farview(ev)
    {
        if (ev.which == 3 || farview_old_vc)
        {
            var offset = $("#minimap").offset();
            if (farview_old_vc === undefined)
            {
                farview_old_vc = {
                    x: dungeon_renderer.view_center.x,
                    y: dungeon_renderer.view_center.y
                }
            }
            var x = Math.round((ev.pageX - display_x - offset.left)
                               / cell_w + cell_x - 0.5);
            var y = Math.round((ev.pageY - display_y - offset.top)
                               / cell_h + cell_y - 0.5);
            vgrdc(x, y);
        }
    }

    function stop_minimap_farview()
    {
        if (farview_old_vc !== undefined)
        {
            vgrdc(farview_old_vc.x, farview_old_vc.y);
            farview_old_vc = undefined;
        }
    }

    $(document).bind("game_init", function () {
        cell_x = cell_y = display_x = display_y = 0;

        $("#minimap_overlay")
            .mousedown(minimap_farview)
            .mousemove(minimap_farview)
            .mouseup(stop_minimap_farview)
    });

    return {
        init_options: init_options,
        fit_to: fit_to,
        update_overlay: update_overlay,
        clear: clear,
        center: center,
        update: update,
        do_view_center_update: do_view_center_update,
        stop_minimap_farview: stop_minimap_farview,
    }
});
