﻿

/******************************** Global Variables **********************************/
var map = new Array();                                      // Global variable for the map object. Set in initialiser!
//var clusterers = new Array();                               // Handles clustering of markers
var geocoder = new GClientGeocoder();                       // Creates a new global geocoding object
var zoomLevels = {
    zoom1: 7,
    zoom2: 9,
    zoom3: 10,
    zoom4: 11,
    zoom5: 12,
    zoom6: 13,
    zoom7: 14,
    zoom8: 15
};                                         // Just sets up the Google zoom level with our 8 zoom levels (you can pick 1-17).
var currZoom = 7                                            // Keeps track of current zoom level
var searchURL = "../Callbacks/GetLocation.aspx?SearchText=" // URL for the searching AJAX to use

/****
* Create a new location icon template
****/
var newLocIcon = new GIcon();
newLocIcon.shadow = "";
newLocIcon.iconSize = new GSize(98, 114);
newLocIcon.iconAnchor = new GPoint(48, 57);
newLocIcon.infoWindowAnchor = new GPoint(50, 28);
newLocIcon.image = '../img/map/new_location.png';

/****
* Create a new position (circle, wanted, item or combination thereof) icon template
****/
var positionIcon = new GIcon();
positionIcon.shadow = "";
positionIcon.iconSize = new GSize(26, 26);
positionIcon.iconAnchor = new GPoint(13, 13);
positionIcon.infoWindowAnchor = new GPoint(13, 13);


var smallPositionIcon = new GIcon();
smallPositionIcon.shadow = "";
smallPositionIcon.iconSize = new GSize(10, 10);
smallPositionIcon.iconAnchor = new GPoint(5, 5);
smallPositionIcon.infoWindowAnchor = new GPoint(5, 5);

/****
* Object to reference the different marker icons that can be put on the map
****/
var markerType = {
    location: '../img/map/your_location.png',
    circle: '../img/map/circle.png',
    item: '../img/map/item.png',
    wanted: '../img/map/wanted.png',
    itemCircle: '../img/map/itemCircle.png',
    itemWanted: '../img/map/itemWanted.png',
    wantedCircle: '../img/map/wantedCircle.png',
    itemWantedCircle: '../img/map/itemWantedCircle.png',
    userSummary: '../img/map/user.png'
}

/****
* Pre load the 8 zoom level images
****/
if (document.images) {
    var zoom1 = new Image(110, 21);
    zoom1.src = '../img/map/zoom_level1.jpg';
    var zoom2 = new Image(110, 21);
    zoom2.src = '../img/map/zoom_level2.jpg';
    var zoom3 = new Image(110, 21);
    zoom3.src = '../img/map/zoom_level3.jpg';
    var zoom4 = new Image(110, 21);
    zoom4.src = '../img/map/zoom_level4.jpg';
    var zoom5 = new Image(110, 21);
    zoom5.src = '../img/map/zoom_level5.jpg';
    var zoom6 = new Image(110, 21);
    zoom6.src = '../img/map/zoom_level6.jpg';
    var zoom7 = new Image(110, 21);
    zoom7.src = '../img/map/zoom_level7.jpg';
    var zoom8 = new Image(110, 21);
    zoom8.src = '../img/map/zoom_level8.jpg';
}

/******************************** Map Initialiser ***********************************/

/****
* Create the map and adds a draggable icon into the middle of it
****/
function initialiseMap(mapID, lat, lng, zoom, width, height, plusID, posnID, minusID) {
    // Check that the browser is compatible with Google maps.
    if (GBrowserIsCompatible()) {
        var centrePoint = new GLatLng(lat, lng);                        // Just sets an initial centre point for the map. Could come from db or something if needed
        map[mapID] = new GMap2(document.getElementById(mapID), { size: new GSize(width, height) }); // This actually creates the map
        //clusterers[mapID] = new Clusterer(map[mapID]);
        //clusterers[mapID].SetMaxVisibleMarkers(4);
        //clusterers[mapID].SetMinMarkersPerCluster(2);
        //clusterers[mapID].SetMaxLinesPerInfoBox(5);
        map[mapID].setCenter(centrePoint, eval('zoomLevels.zoom' + currZoom)); // Sets the centre point for the map and the initial zoom level
    } else {
        alert("Sorry, the Google Maps API is not compatible with this browser");
        return
    }

    // Restrict the range of zoom levels to those we allow
    var mt = map[mapID].getMapTypes();
    // Overwrite the getMinimumResolution() and getMaximumResolution() methods
    for (var i = 0; i < mt.length; i++) {
        mt[i].getMinimumResolution = function() { return 6; }
        mt[i].getMaximumResolution = function() { return 15; }
    }

    // Now initialise the map zoom control
    initialiseZoomControl(mapID, plusID, posnID, minusID);

    // Add the unload function to trigger when leaving the page to cleanup things..
    $('body').unload(function() {
        GUnload();
    });
}


function addOverlay(mapID, marker) {
    //clusterers[mapID].AddMarker(marker, '');
    map[mapID].addOverlay(marker);
}


/****
* Initialises the zoom control, adds zoom events to elements.
****/
function initialiseZoomControl(mapID, plusID, posnID, minusID) {
    // Binds the click event to the plus and minus buttons on the page.
    $('#' + plusID).click(function() {
        currZoom = parseInt(currZoom) + 1;
        if (currZoom > 8)
            currZoom = 8;
        map[mapID].setZoom(eval('zoomLevels.zoom' + currZoom));
        $('#' + posnID).attr('src', eval('zoom' + currZoom + '.src'));
        var message = document.getElementById('mapMessage');
        if (message != null) {
            document.getElementById('mapMessage').innerHTML = 'To pan map: click, hold & drag';
        }

    }).css('cursor', 'pointer');

    $('#' + minusID).click(function() {
        currZoom = parseInt(currZoom) - 1;
        if (currZoom < 1)
            currZoom = 1;
        map[mapID].setZoom(eval('zoomLevels.zoom' + currZoom));
        $('#' + posnID).attr('src', eval('zoom' + currZoom + '.src'));
        var message = document.getElementById('mapMessage');
        if (message != null) {
            document.getElementById('mapMessage').innerHTML = 'Wider view on the same results';
        }
    }).css('cursor', 'pointer');

    // If user has double clicked to zoom the map, then need to capture the end event and update the zoom control
    GEvent.addListener(map[mapID], "zoomend", function() {
        var thisZoom = map[mapID].getZoom();
        $('#' + posnID).attr('src', eval('zoom' + convertGZoomToEcoZoom(thisZoom) + '.src'));
    });
    setZoom(mapID, currZoom);
}

/******************************** Map functions *************************************/
/****
* Updates out curr pre-defined zoom levels and does the appropriate conversion for GMaps.
****/
function setZoom(mapID, zoomLevel) {
    map[mapID].setZoom(eval("zoomLevels.zoom" + zoomLevel));
    currZoom = zoomLevel;
}

/****
* Takes the object array with items, circles, etc and adds them to the map
****/
function addMapElements(mapID, objElements) {
    // If the object's empty, do nothing
    if (objElements == null || objElements.length == 0)
        return;

    // Clear all overlays from the map first
    map[mapID].clearOverlays();

    // You set an arbitrary centre and create an empty bounds object
    // This is used to set the zoom to show all elements added to the map.
    map[mapID].setCenter(new GLatLng(0, 0), 0);
    var bounds = new GLatLngBounds();

    // For each element, create a marker and add it to the map
    for (var i = 0; i < objElements.length; i++) {
        // Create a new marker for an item (green circle).
        // This one is not clickable as the html parameter is set to null.
        var myMarker = createMarker(objElements[i].point, objElements[i].type, objElements[i].objInfo);

        // Add the new point into the bounds object
        bounds.extend(objElements[i].point);

        // Now add the marker to the map.
        //clusterers[mapID].AddMarker(myMarker, '');
        map[mapID].addOverlay(myMarker);
    }

    // Now have all points in the bounds object, so can set the centre and zoom level of the map to show all elments
    setZoom(mapID, convertGZoomToEcoZoom(map[mapID].getBoundsZoomLevel(bounds)));
    map[mapID].setCenter(bounds.getCenter());
}

/****************************** Draggable Markers ***********************************/

/****
* Create a draggable new location marker for the map
****/
function createDraggableMarker(mapID, point, html) {
    var options = {};
    var customIcon = new GIcon(newLocIcon);  // newLocIcon is defined at the top of this script

    options = { icon: customIcon, draggable: true };
    var marker = new GMarker(point, options);

    // Add a click event to the marker to display the info window when marker clicked.
    GEvent.addListener(marker, "click", function() {
        marker.openInfoWindowHtml(html);
    });

    // Close the info window when the marker starts to be dragged on the map.
    GEvent.addListener(marker, "dragstart", function() {
        map[mapID].closeInfoWindow();
    });

    // When the icon is dropped, get it's current position and zoom level and could save to db or something. 
    // Currently just pans the map so the icon is in the centre all the time.
    GEvent.addListener(marker, "dragend", function(e, x, y) {
        var point = marker.getPoint();
        var zoom = map[mapID].getZoom();

        // Centre the map on the new point and keeping the same zoom level
        map[mapID].panTo(point, zoom);

        // You can just have the values as hidden fields on the page and fill them in here ready for submission.
        // Alternatively you can do an AJAX callback in the normal way with the data if it's easier/required
        $('#lat').val(point.lat());
        $('#lng').val(point.lng());
        $('#zoom').val(zoom);
    });

    return marker;
}

/****
* Creates a static new marker to add to the map
****/
function createMarker(point, type, objElemInfo) {
    var customIcon;

    if (type == markerType.circle || type == markerType.item || type == markerType.wanted) {
        customIcon = new GIcon(positionIcon);
    } else if (type == markerType.userSummary) {
        customIcon = new GIcon(smallPositionIcon);
    } else {
        customIcon = new GIcon(positionIcon);
    }

    customIcon.image = type;

    var options = { icon: customIcon, draggable: false };
    var marker = new GMarker(point, options);

    // Add a click event to the marker to display the info window when marker clicked.
    if (objElemInfo != null) {
        if (type == markerType.circle || type == markerType.item || type == markerType.wanted) {
            var bubble = createSingleElemBubble(type, objElemInfo);
        } else if (type == markerType.userSummary) {
            var bubble = createSimpleBubble(objElemInfo);
        } else {
            var bubble = createMultiElemBubble(objElemInfo);
        }

        GEvent.addListener(marker, "click", function() {
            marker.openInfoWindow(bubble);
        });
    }

    return marker;
}

/********************************** Searching ***************************************/

/****
* Makes the call to the Google geocoder
****/
function getSearchLocations(mapID, searchText) {
    var searchText
    // Need to have some text to do something with
    if (searchText == '' || searchText == null)
        return;
    // Restrict responses to only the UK
    if (searchText.indexOf('UK') == -1)
        searchText += ', UK';
    geocoder.getLocations(searchText, function(response) {
        var output = '';
        var place = '';

        map[mapID].clearOverlays();

        if (!response || response.Status.code != 200) {
            // If there's been an error, just say address not found. Actually a list of errors returned if you want to use them.
            showResults('Address not found');
        } else {

            if (response.Placemark.length == 1) {
                // If only one placemark, just display it on the map.
                hideResults();
                place = response.Placemark[0];  // Get the current place details from the json response array

                showPlaceOnMap(mapID, place.Point.coordinates[1], place.Point.coordinates[0], place.address)
            } else {
                // If multiple places returned, build a list and display them. Put in an anchor tag to display the place on the map when clicked.
                for (var i = 0; i < response.Placemark.length; i++) {
                    place = response.Placemark[i]; // Get the current place details from the json response array
                    output += '<a href="Javascript:showPlaceOnMap(\'' + mapID + '\', \'' + place.Point.coordinates[1] + '\', \'' + place.Point.coordinates[0] + '\', \'' + place.address + '\');">' + place.address.replace(', UK', '').replace(', United Kingdom', '') + '</a><br />';
                }

                showResults(output);
            }
        }
    });
}



/****
* Centres the map on the place selected from the drop down box
****/
function showPlaceOnMap(mapID, lat, lng, place) {
    // If no lat/long then don't do anything as it's going to cause problems.
    if (lat == '' || lng == '')
        return;

    map[mapID].clearOverlays();

    // create the point and pan the map to the point. Could use setCentre if you don't want the map to animate.
    var point = new GLatLng(lat, lng);

    map[mapID].panTo(point, eval('zoomLevels.zoom' + currZoom));
    // Adds a draggable marker to the centre of the map
    var myMarker = createDraggableMarker(mapID, point, place);
    map[mapID].addOverlay(myMarker);
}

/****
* Just opens the results element with the results in
****/
function showResults(html) {
    $('#div_results').slideUp('slow', function() {
        $('#results').html(html);
        $('#div_results').slideDown('slow');
    });
}

/****
* Closes the results
****/
function hideResults() {
    $('#div_results').slideUp('slow', function() {
        $('#results').html('');
    });
}

/****
* Takes the zoom level returned by Google and converts it into one of the Ecomodo 8 zoom levels
****/
function convertGZoomToEcoZoom(gZoom) {
    if (parseInt(gZoom) <= 7)
        return '1';
    else if (parseInt(gZoom) <= 9)
        return '2';
    else if (parseInt(gZoom) == 10)
        return '3';
    else if (parseInt(gZoom) == 11)
        return '4';
    else if (parseInt(gZoom) == 12)
        return '5';
    else if (parseInt(gZoom) == 13)
        return '6';
    else if (parseInt(gZoom) == 14)
        return '7';
    else if (parseInt(gZoom) >= 15)
        return '8';
}

/****
* Creates the infoWindow html for a single item, circle or wanted
****/
function createSingleElemBubble(type, objItemInfo) {
    var bubble = document.createElement("div");
    bubble.className = "mapBox contain";
    var top = document.createElement("div");
    top.className = "mapBoxTop";
    var content = document.createElement("div");
    content.className = "cont";
    bubble.appendChild(top);
    bubble.appendChild(content);

    var depositLine = ""
    var costTitle = ""
    var IncludesInsuranceLine = ""
    var ImagePadding = "135"
    var ItemTypeTitle = ""
    var ItemImageHTML = ""
    var ItemCost = ""
    var ItemWho = ""
    var ViewLink = ""
    var IntendedUse = ""

    if (type == markerType.circle) { //CIRCLE
        ItemTypeTitle = '<span class="pink">Circle: </span>';
        ImagePadding = "0";
        ViewLink = '<li class="last floatRight"><a href="' + objItemInfo.viewLink + '" id="hyp_itemView" class="pink">Visit Circle</a></li>';
        ItemWho = '<li>' + objItemInfo.description + '</li>'; 
        //TODO: add in circle logo for ItemImageHTML and take out imagePadding above

    } else if (type == markerType.wanted) { //WANTED
        ItemTypeTitle = '<span class="orange">Wanted: </span>';
        ImagePadding = "0";
        ViewLink = '<li class="last floatRight"><a href="' + objItemInfo.viewLink + '" id="hyp_itemView" class="orange">View Wanted Ad</a></li>';
        ItemWho = '<li><span>borrower</span> ' + objItemInfo.wanter + '</li>';
        IntendedUse = '<li><span>intended use</span> ' + objItemInfo.intendeduse + '</li>';
    } else { //ITEM
        ItemImageHTML = '<div class="Outline" style="margin-bottom:8px;"><img src="' + objItemInfo.imgURL + '" width="127" height="127" id="img_itemRoll" alt="' + objItemInfo.title + '" /></div>';
        //if (objItemInfo.costPeriod = 0) { //TODO: add all options in
        costTitle = 'cost per day';
        //} else if (objItemInfo.costPeriod = 1) {
        //    costTitle = 'cost per week';
        //}
        ItemCost = '<li><span>' + costTitle + '</span> ' + objItemInfo.cost + '</li>';
        ItemWho = '<li><span>lender</span> ' + objItemInfo.lender + '</li>';
        ViewLink = '<li class="last floatRight"><a href="' + objItemInfo.viewLink + '" id="hyp_itemView">View Item</a></li>';
        //alert(objItemInfo.insurance);
        if (objItemInfo.insurance != "") {
            IncludesInsuranceLine = '<li><span>' + objItemInfo.insurance + '</span></li>';
        }
        if (objItemInfo.depositamount != "") {
            depositLine = '<li><span>deposit</span> ' + objItemInfo.depositamount + '</li>';
        }
    }

    content.innerHTML = ''
                      + '<h2>' + ItemTypeTitle + objItemInfo.title + '</h2>'
                      + ItemImageHTML
                      + '<ul id="costs" style="margin-left:0px; padding-left:' + ImagePadding + 'px;">'
                      + ItemCost
                      + IncludesInsuranceLine
                      + depositLine
                      + '</ul>'
                      + '<ul id="details" style="margin-left:0px; padding-left:' + ImagePadding + 'px; padding-bottom:5px;">'
                      + IntendedUse
                      + ItemWho
    //+ '   <li><span>feedback</span> ' + objItemInfo.feedback + '</li>'
                      + '   <li><span>location</span> ' + objItemInfo.location + '</li>'
                      + '   <li><span id="txt_distance">' + objItemInfo.distance + '</span></li>'
                      + '</ul>'
                      + '<div class="hr" style="margin-bottom: 0px 0px 4px 0px;"></div>'
                      + '<ul class="Action contain" style="float:right;">'
                      + ViewLink
                      + '</ul>'
    //+ '<p class="floatRight"><input type="image" alt="Send Request" src="../img/buttons/btnSendRequest.gif"/></p>';
    // Just in case. It doesn't work within google maps though
    //+'   <li class="last"><a href="#" id="hyp_itemFlag">Flag</a></li>'

    return bubble;
}



function createSimpleBubble(objItemInfo) {
    var bubble = document.createElement("div");
    bubble.className = "mapBox contain";
    var top = document.createElement("div");
    top.className = "mapBoxTop";
    var content = document.createElement("div");
    content.className = "cont";
    bubble.appendChild(top);
    bubble.appendChild(content);

    content.innerHTML = '<h2>' + objItemInfo.title + '</h2>';

    return bubble;
}





/****
* Creates the infoWindow html for elements with multiple items in them.
****/
function createMultiElemBubble(objItemInfo) {
    // Create the DOM elements needed for the surround
    var bubble = document.createElement("div");
    bubble.className = "mapBox contain";
    var top = document.createElement("div");
    top.className = "mapBoxTop";
    var content = document.createElement("div");
    content.className = "cont";
    bubble.appendChild(top);
    bubble.appendChild(content);

    var numItems = 0;
    var numCircles = 0;
    var numWanted = 0;
    var items = '';
    var circles = '';
    var wanted = '';
    var elemContent = '';
    var iCount = 0;
    var iCount2 = 0;

    // Go through the objItemInfo and see what there is to display
    for (iCount = 0; iCount < objItemInfo.length; iCount++) {
        if (objItemInfo[iCount].type == 'item') {
            numItems = objItemInfo[iCount].elems.length;
            for (iCount2 = 0; iCount2 < objItemInfo[iCount].elems.length; iCount2++) {
                items += ''
                      + '<p>' + objItemInfo[iCount].elems[iCount2].title + '</p>'
                      + '<ul class="green1List">'
                      + '   <li class="end"><a href="object_viewObject_v2.html?itemID=' + objItemInfo[iCount].elems[iCount2].itemID + '">view</a></li>'
                      + '</ul>'
                      + '<div class="clear"></div>';
            }
        } else if (objItemInfo[iCount].type == 'circle') {
            numCircles = objItemInfo[iCount].elems.length;
            for (iCount2 = 0; iCount2 < objItemInfo[iCount].elems.length; iCount2++) {
                circles += ''
                      + '<p>' + objItemInfo[iCount].elems[iCount2].title + '</p>'
                      + '<ul class="purpleList">'
                      + '   <li class="end"><a href="circles_itemsFromACircle_member_v2.html?circleID=' + objItemInfo[iCount].elems[iCount2].itemID + '">view</a></li>'
                      + '</ul>'
                      + '<div class="clear"></div>';
            }
        } else if (objItemInfo[iCount].type == 'wanted') {
            numWanted = objItemInfo[iCount].elems.length;

            for (iCount2 = 0; iCount2 < objItemInfo[iCount].elems.length; iCount2++) {
                wanted += ''
                      + '<p>' + objItemInfo[iCount].elems[iCount2].title + '</p>'
                      + '<ul class="orange1List">'
                      + '   <li class="end"><a href="object_viewObject_v2.html?itemID=' + objItemInfo[iCount].elems[iCount2].itemID + '">view</a></li>'
                      + '</ul>'
                      + '<div class="clear"></div>';
            }
        }
    }
    // Just in case. It doesn't work within google maps though...
    //+'   <li class="end"><a href="#">flag</a></li>'

    // Now create the strings to add into the main content area
    if (numItems > 0) {
        elemContent += ''
                     + '<h2 class="green">items to lend</h2>'
                     + items;
    }
    if (numWanted > 0) {
        elemContent += ''
                     + '<h2 class="orange">wanted ads</h2>'
                     + wanted;
    }
    if (numCircles > 0) {
        elemContent += ''
                     + '<h2 class="pink">circles</h2>'
                     + circles;
    }

    // Add in the content
    content.innerHTML = ''
                      + '<p class="titleList" id="txt_charity">'
                      + '   <span class="green">' + numItems + '</span> items to lend '
                      + '   <span class="orange">' + numWanted + '</span> wanted ads '
                      + '   <span class="pink">' + numCircles + '</span> circles'
                      + '</p>'
                      + '<div class="hr"></div>'
                      + '<div class="mapItems">'
                      + elemContent
                      + '</div>'
                      + '<div class="hr"></div>';

    return bubble;
}

/****
* Checks for a valid postcode
****/
function isPostcode(inPost) {
    if (inPost.match(/^(GIR|[A-Z]\d[A-Z\d]??|[A-Z]{2}\d[A-Z\d]??)[ ]??(\d[A-Z]{2})$/i))
        return true;
    else
        return false;
}

/****
* Checks for the first part of a postcode (N1, W1B, SE21, ...)
****/
function isPartPostcode(inPost) {
    if (inPost.match(/^([A-PR-UWYZ0-9][A-HK-Y0-9][AEHMNPRTVXY0-9]?[ABEHMNPRVWXY0-9])$/i))
        return true;
    else
        return false;
}
