/*
 * Configuration: Edit the following 8 settings.
 */
 
// Path to the JSON describing the map pins.
var js_mapping_map_pins_json = "helpers/map_pin_json.php";

// Number of map tiles horizontally. If using one image, set to 1.
var js_mapping_num_tiles_x = 10;

// Number of map tiles vertically. If using one image, set to 1.
var js_mapping_num_tiles_y = 10;

// Width in pixels of each map tile. If using one image, set to the full width of the image.
var js_mapping_tile_width = 350;

// Height in pixels of each map tile. If using one image, set to the full height of the image.
var js_mapping_tile_height = 280;

// Coordinates on which to center the map.
var js_mapping_center_coordinates = {x: 1025, y: 1675};

/*
 * END CONFIGURATION. You don't need to edit anything below this line.
 */

// Width in pixels of the map view.
var js_mapping_view_width = parseInt($("#js_mapping_holder").css('width'));

// Height in pixels of the map view.
var js_mapping_view_height = parseInt($("#js_mapping_holder").css('height'));

// Keep track of downloaded map tiles
var js_mapping_tiles = [];
for(i = 0; i < js_mapping_num_tiles_y; i++) {
    js_mapping_tiles[i] = [];
    for (j = 0; j < js_mapping_num_tiles_x; j++) {
        js_mapping_tiles[i][j] = false;
    }
}

// Function to add a map tile to the map
function js_mapping_add_tile(i, j) {
    if (i < 0 || j < 0 || i >= js_mapping_num_tiles_y || j >= js_mapping_num_tiles_x) {
        return;
    }
    
    if (js_mapping_tiles[i][j]) {
        return;
    }
    
    $("#js_mapping_handle").append(
        "<img src='map_tiles/map_tile" +
        i +
        "-" +
        j + 
        ".jpg' style='z-index:2;position:absolute;top:" +
        js_mapping_tile_height*i +
        "px;left:" +
        js_mapping_tile_width*j +
        "px'>");
    js_mapping_tiles[i][j] = true;
}

function js_mapping_update_tiles_snapback() {
    js_mapping_update_tiles(true);
}

function js_mapping_update_tiles_stay() {
    js_mapping_update_tiles(false);
}

// Function to update the tiles on the map based on current position
function js_mapping_update_tiles(snapback) {
    map = $("#js_mapping_draggable");
    position = map.position();
    
    // Keep the map in the horizontal and vertical dimensions
    if (snapback) {
        if (position.left > 0) {
            position.left = 0;
        } else if (position.left < -1*js_mapping_num_tiles_x*js_mapping_tile_width+js_mapping_view_width) {
            position.left = -1*js_mapping_num_tiles_x*js_mapping_tile_width+js_mapping_view_width;
        }
        if (position.top > 0) {
            position.top = 0;
        } else if (position.top < -1*js_mapping_num_tiles_y*js_mapping_tile_height+js_mapping_view_height) {
            position.top = -1*js_mapping_num_tiles_y*js_mapping_tile_height+js_mapping_view_height;
        }
        map.animate(position, 100);
    }
    
    top_start_tile = parseInt(-1*position.top/js_mapping_tile_height);
    left_start_tile = parseInt(-1*position.left/js_mapping_tile_width);
    top_end_tile = parseInt(js_mapping_view_height/js_mapping_tile_height)+top_start_tile;
    left_end_tile = parseInt(js_mapping_view_width/js_mapping_tile_width)+left_start_tile;
    for (i = top_start_tile-1; i<=top_end_tile+1; i++) {
        for (j = left_start_tile-1; j<=left_end_tile+1; j++) {
            js_mapping_add_tile(i, j);
        }
    }
}

// Function to place a pin on the map
function js_mapping_place_pin(pin) {
    $("#js_mapping_draggable").append("<div class='js_mapping_map_pin' id='js_mapping_pin_" +
    pin.loc_id +
    "' style='position:absolute;top:" +
    (pin.y-29) + "px;left:" + (pin.x) +
    "px'></div><div class='js_mapping_map_pin_info' id='js_mapping_pin_" +
    pin.loc_id +
    "_info' style='position:absolute;top:" +
    (pin.y-35-90) + "px;left:" + (pin.x+21) +
    "px;display:none'></div>");
    $("#js_mapping_holder:not(.js_mapping_admin) #js_mapping_pin_"+pin.loc_id+"_info").text(pin.name + ": " + pin.num_bikes + " bikes available");
    $(".js_mapping_admin #js_mapping_pin_"+pin.loc_id+"_info")
        .addClass('js_mapping_map_pin_info_admin')
        .css("top", pin.y-35-160)
        .append("<form method='post' action='helpers/map_pin_edit.php' class='js_mapping_edit_form'>" +
                "<input type='hidden' name='loc_id' value='"+pin.loc_id+"'/>" +
                "<label for='edit_name' class='js_mapping_info_label'>location name</label>" +
                "<input type='text' class='js_mapping_info_input' name='name' id='edit_name' value='"+pin.name+"'/>" +
                "<label for='edit_num_bikes' class='js_mapping_info_label'>number of bikes available</label>" +
                "<input type='text' class='js_mapping_info_input' name='num_bikes' id='edit_num_bikes' value='"+pin.num_bikes+"'/>" +
                "<input type='submit' class='js_mapping_edit_submit' value='edit'/>" +
                "</form>")
        .append("<form method='post' action='helpers/map_pin_remove.php' class='js_mapping_remove_form'>" +
                "<input type='hidden' name='loc_id' value='"+pin.loc_id+"'/>" +
                "<input type='submit' class='js_mapping_remove_submit' value='remove'/>" +
                "</form>");
    $(".js_mapping_admin #js_mapping_pin_"+pin.loc_id+"_info .js_mapping_remove_form").submit(remove_form_submitter);
    $(".js_mapping_admin #js_mapping_pin_"+pin.loc_id+"_info .js_mapping_edit_form").submit(edit_form_submitter);
    $("#js_mapping_pin_"+pin.loc_id+"_info").data("loc_id", pin.loc_id);
}

// Function to display a form to accept a new map pin
function js_mapping_make_new_pin(x, y) {
    // Insert the new pin and the input form
    $("#js_mapping_draggable").append("<div class='js_mapping_map_pin js_mapping_add_pin' id='js_mapping_pin_" +
    y+"-"+x +
    "' style='position:absolute;top:" +
    (y-29) +
    "px;left:" +
    (x) +
    "px'></div><div class='js_mapping_map_pin_info js_mapping_map_pin_info_admin' id='js_mapping_pin_" +
    y+"-"+x +
    "_info' style='position:absolute;top:" +
    (y-35-160) +
    "px;left:" +
    (x+21) +
    "px;display:none'>" +
    "<form method='post' action='helpers/map_pin_add.php' id='js_mapping_add_form_"+y+"-"+x+"'>" +
    "<label for='js_mapping_add_name' class='js_mapping_info_label'>location name</label>" +
    "<input type='text' id='js_mapping_add_name' class='js_mapping_info_input' name='name'/>" +
    "<label for='add_map_pin_number' class='js_mapping_info_label'>number of bikes available</label>" +
    "<input type='text' class='js_mapping_info_input' id='add_map_pin_number' name='num_bikes'/>" +
    "<input type='submit' class='js_mapping_add_submit' value='add rack'/>" +
    "<input type='reset' class='js_mapping_add_cancel' value='cancel'/>" +
    "</form>" +
    "</div>");
    
    // Set up the "delete this pin" functionality
    $("#js_mapping_pin_"+y+"-"+x+"_info .js_mapping_add_cancel").click(function() {
        $("#js_mapping_pin_"+y+"-"+x).remove();
        $("#js_mapping_pin_"+y+"-"+x+"_info").remove();
    });
    
    // Set up the "add this pin" functionality
    $("#js_mapping_add_form_"+y+"-"+x).submit(function() {
        $(this).find(".js_mapping_add_submit")
            .attr('disabled', 'disabled')
            .addClass("js_mapping_loading")
            .val("adding...");
        
        $.post(this.action,
            {"name": this.name.value,
             "num_bikes": this.num_bikes.value,
             "position_x": x,
             "position_y": y},
            function(data) {
                 $(".js_mapping_add_submit").removeAttr('disabled').removeClass("js_mapping_loading").val("add rack");
                if (data.pin && !data.pin.error) {
                    $("#js_mapping_pin_"+y+"-"+x+"_info").remove();
                    $("#js_mapping_pin_"+y+"-"+x).remove();
                    js_mapping_place_pin(data.pin);
                    $("#js_mapping_pin_"+data.pin.loc_id).click();
                } else {
                    alert("Error: " + data.pin.error);
                }
            },
            "json");
        return false;
    });
    
    // Focus on the new pin and focus on the first input
    $("#js_mapping_pin_"+y+"-"+x).click();
    $("#js_mapping_pin_"+y+"-"+x+"_info .js_mapping_info_input:first").focus();
}

// Function to find the offset of an object
function find_offset(obj) {
    curleft = curtop = 0;
    if (obj.offsetParent) {
        do {
            curleft += obj.offsetLeft;
            curtop += obj.offsetTop;
        } while (obj = obj.offsetParent);
    }
    return {left: curleft, top: curtop};
}

// Function to be called on the submit event of an edit form
// We could use an inline anonymous function with live queries,
// but the submit event is not supported by live() yet
function edit_form_submitter() {
    $(this).find(".js_mapping_edit_submit")
        .attr('disabled', 'disabled')
        .addClass("js_mapping_loading")
        .val("editing...");

    $.post(this.action,
        {"loc_id": this.loc_id.value,
         "name": this.name.value,
         "num_bikes": this.num_bikes.value},
        function(data) {
             $(this).find(".js_mapping_edit_submit").removeAttr('disabled').removeClass("js_mapping_loading").val("edit");
            if (data.pin && !data.pin.error) {
                $("#js_mapping_pin_"+data.pin.loc_id+"_info").remove();
                $("#js_mapping_pin_"+data.pin.loc_id).remove();
                js_mapping_place_pin(data.pin);
                $("#js_mapping_pin_"+data.pin.loc_id).click();
            } else {
                alert("Error: " + data.pin.error);
            }
        },
        "json");
    return false;
}

// Function to be called on the submit event of a remove form
// We could use an inline anonymous function with live queries,
// but the submit event is not supported by live() yet
function remove_form_submitter() {
    $(this).find(".js_mapping_remove_submit")
        .attr('disabled', 'disabled')
        .addClass("js_mapping_loading")
        .val("removing...");

    $.post(this.action,
        {"loc_id": this.loc_id.value},
        function(data) {
            $(this).find(".js_mapping_remove_submit").removeAttr('disabled').removeClass("js_mapping_loading").val("remove");
            if (data !== "failure") {
                $("#js_mapping_pin_"+data+"_info").remove();
                $("#js_mapping_pin_"+data).remove();
            } else {
                alert("Error: " + data);
            }
        },
        "text");
    return false;
}

$(document).ready(function() {
    // Set up the draggable map
    $("#js_mapping_draggable")
        .draggable({
            stop: js_mapping_update_tiles_snapback,
            handle: "#js_mapping_handle"
        })
        .css("width", js_mapping_tile_width*js_mapping_num_tiles_x)
        .css("height", js_mapping_tile_height*js_mapping_num_tiles_y)
        .css("left", (js_mapping_view_width/2)-js_mapping_center_coordinates.x)
        .css("top", (js_mapping_view_height/2)-js_mapping_center_coordinates.y);
    
    // Set up the draggable handle
    $("#js_mapping_handle").click(function() {
        $(".js_mapping_map_pin_info").hide();
        $(".js_mapping_add_pin").remove();
        $(".js_mapping_add_info").remove();
    });
    
    // Set up the navigation
    $("#js_mapping_nav_up").click(function() {
        $("#js_mapping_draggable").animate({top: "+="+js_mapping_view_height/4}, 100, null, js_mapping_update_tiles_snapback);
        return false;
    });
    $("#js_mapping_nav_left").click(function() {
        $("#js_mapping_draggable").animate({left: "+="+js_mapping_view_width/4}, 100, null, js_mapping_update_tiles_snapback);
        return false;
    });
    $("#js_mapping_nav_right").click(function() {
        $("#js_mapping_draggable").animate({left: "-="+js_mapping_view_width/4}, 100, null, js_mapping_update_tiles_snapback);
        return false;
    });
    $("#js_mapping_nav_down").click(function() {
        $("#js_mapping_draggable").animate({top: "-="+js_mapping_view_height/4}, 100, null, js_mapping_update_tiles_snapback);
        return false;
    });
    
    // Retrieve and set up the map pins
    $.get(js_mapping_map_pins_json, {},
        function(data) {
            $.each(data.pins, function(i, pin) {
                js_mapping_place_pin(pin);
            });
        }, "json");
    $(".js_mapping_map_pin").live("click", function() {
        $(".js_mapping_map_pin_info:not(#" + this.id + "_info)").hide();
        $("#" + this.id + "_info").toggle();
        $("#js_mapping_draggable")
            .animate({ left:-1*$(this).position().left+js_mapping_view_width/2-110,
                       top:-1*$(this).position().top+js_mapping_view_height/2+55},
                     100, null, js_mapping_update_tiles_stay);
    });
    $("#js_mapping_show_pins").click(function() {
        if ($("#js_mapping_show_pins:checked").length > 0) {
            $(".js_mapping_map_pin").show();
        } else {
            $(".js_mapping_map_pin").hide();
            $(".js_mapping_map_pin_info").hide();
        }
    });
    
    // Set up the admin pin-adding features
    $(".js_mapping_admin #js_mapping_draggable").dblclick(function(click_event) {
        offset = find_offset(this);
        js_mapping_make_new_pin(click_event.pageX-offset.left, click_event.pageY-offset.top);
    });
    
    // Download the current tiles
    js_mapping_update_tiles_snapback();
});