﻿var countObject;
var currentPage = 1;
var map;
var autoFit = true;
var bounds = new GLatLngBounds();
var resultsCache;
var labelMode;
var imageBase;

var longitude;
var latitude;
var radius;
var moduleIds;
var objectTypeIds;

var currentSearchRadius;
var manager;

//default icon
var icon = new GIcon(G_DEFAULT_ICON);
icon.image = "http://www.google.com/intl/en_us/mapfiles/ms/micons/red.png";
icon.iconSize = new GSize(32,32);
icon.shadowSize = new GSize(59,32);


//Proxy search methods

function DoProxySearch() {
    countObject = search.proxysearchcount(longitude, latitude, radius, moduleIds, objectTypeIds, 25);
    resultsCache = new Array(countObject.totalPages);
    pageLinksHtml = "";
    for (i = 0; i < countObject.totalPages; i++) {
        pageLinksHtml += "<a href=\"javascript:ShowPage(" + (i + 1) + ");\">" + (i + 1) + "</a>";
        if (i < countObject.totalPages - 1) {
            pageLinksHtml += " | ";
        }
    }
    document.getElementById("PageLinks").innerHTML = pageLinksHtml;
    ShowPage(1);
}

function SetAutoFit(checkBox) {
    autoFit = checkBox.checked;
}

function ShowPage(pageNo) {
    map.clearOverlays();
    
    if (currentSearchRadius != null) {
        map.addOverlay(currentSearchRadius);
    }
    bounds = new GLatLngBounds();
    var results;
    results = search.proxysearch(longitude, latitude, radius, moduleIds, objectTypeIds, pageNo, countObject.pageSize, labelMode);
    resultsCache[pageNo - 1] = results;
   
    if (resultsCache[pageNo - 1] == null) {
        results = search.proxysearch(longitude, latitude, radius, moduleIds, objectTypeIds, pageNo, countObject.pageSize, labelMode);
        resultsCache[pageNo - 1] = results;
    } else {
        results = resultsCache[pageNo - 1];
    }
    for (i = 0; i < results.length; i++) {
        var point = new GLatLng(results[i].latitude, results[i].longitude);
        bounds.extend(point);
        map.addOverlay(CreatePoint(results[i].hTML, point, results[i].label));
    }
    if (autoFit) {
        map.setZoom(map.getBoundsZoomLevel(bounds));
        map.setCenter(bounds.getCenter());
    }
}

//browse methods
function Browse() {
    //clear all of our markers
    map.clearOverlays();
    //grab the visible bounds
    var bounds = map.getBounds();
    //grab our two corners
    var northEast = bounds.getNorthEast();
    var southWest = bounds.getSouthWest();
    //do our search
    var results = search.browse(northEast.lng(), northEast.lat(), southWest.lng(), southWest.lat(), moduleIds, objectTypeIds);
    //show our results
    for (i = 0; i < results.length; i++) {
        var point = new GLatLng(results[i].latitude, results[i].longitude);
        bounds.extend(point);
//        var marker = CreatePointBrowse(results[i].hTML, point, results[i].label);
//        
        var points = new Array();
        
        for (j = 0; j < results[i].polygonLatLongs.length; j+= 2) {
            points.push(new GLatLng(results[i].polygonLatLongs[j], results[i].polygonLatLongs[j + 1]));
        }
	    var polygon = new GPolygon(points, "#000000", 5, 0.25, "#ff0000", 0.25)        
        var marker = new CreatePointBrowse(results[i].hTML, point, polygon, results[i].activity);
        map.addOverlay(marker);
    }
}

function ZIndexStack(a, b) {
    return 1;
}

function CreatePoint(html, position, icon, label) {
    var localIcon = icon;
    if (label != null && label != "") {
        var localIcon = new GIcon(G_DEFAULT_ICON);
        localIcon.image = imageBase + label + ".png";
        localIcon.iconSize = new GSize(32,32);
        localIcon.shadowSize = new GSize(59,32);
    }
    var marker = new GMarker(position, {icon:localIcon, zIndexProcess:ZIndexStack});
    GEvent.addListener(marker, "click", function() {marker.openInfoWindowHtml(html);});
    bounds.extend(position);
    return marker;
}


function CreatePointBrowse(html, position, polygon, activity) {
    var localIcon = new GIcon(G_DEFAULT_ICON);
    localIcon.image = imageBase + "Button.png";
    localIcon.shadow = "";
    var widthHeight = 10 + ((40 / 100) * activity);
    localIcon.iconAnchor = new GPoint(widthHeight / 2, widthHeight / 2);
    localIcon.iconSize = new GSize(widthHeight,widthHeight);
    var imageMap = new Array();
    for (y = 0; y < widthHeight; y++) {
        for (x = 0; x < widthHeight; x++) {
            imageMap.push(x);
            imageMap.push(y);
        }
    }
    localIcon.imageMap = imageMap;
    
    var marker = new GMarker(position, localIcon);
    marker.polygon = polygon;
    GEvent.addListener(marker, "click", function() {
            marker.openInfoWindowHtml(html);
            if (marker.polygon != null) {
                map.addOverlay(marker.polygon);
                if (polyLine != null) {
                    map.removeOverlay(polyLine);
                }
                polyLine = marker.polygon;
            }
        }
    );
    bounds.extend(position);
    return marker;
}

var guiProxyEnabled = false;
var enableButton;



function EnableGUIProxySearch(button) {
    //make sure we're handling the first time we click the map only
    firstClick = true;
    //disable dragging on the map
    map.disableDragging();
    //don't allow the user to start another search until this one is finished!
    enableButton = button;
    button.disabled = true;
    //now we can pass control over to our handlers
    guiProxyEnabled = true;
    //just to make sure
    dragging = false;
}

function DisableGUIProxySearch() {
    //remove control from our handlers
    guiProxyEnabled = false;
    //allow the user to start another search
    enableButton.disabled = false;
    //re-enable dragging
    map.enableDragging();
    //just to make sure
    dragging = false;
}

//indicates whether the user has clicked the map once when in proxy search mode
var dragging = false;
//indicates whether this is the first or second click
var firstClick = true;
//the GLatLog of the first click
var startDrag;
//the GLatLog of the second click
var endDrag;
//our polygon showing the search area
var polyLine;
//just an additional flag
var searchFlag = false;

function HandleGMapClick(point) {
    //make sure we should be handling this
    if (guiProxyEnabled) {
        //is this the first time the user has clicked the map?
        if (firstClick) {
            //yes it is, just set our flags and our position
            firstClick = false;
            startDrag = point;
            dragging = true;
        } else {
            //called the second time we click the map
            guiProxyEnabled = false;
            dragging = false;
            DisableGUIProxySearch();
            longitude = startDrag.lng();
            latitude = startDrag.lat();
            radius = startDrag.distanceFrom(endDrag) / 1000;
            DoProxySearch();
        }
    }
}

function HandleGMapMouseMove(point) {
    if (dragging && guiProxyEnabled) {
        window.status = point.toString();
        map.clearOverlays();
        endDrag = point;
        var pixelStart = map.fromLatLngToDivPixel(startDrag);
        var pixelEnd = map.fromLatLngToDivPixel(point);
        var deltaX = pixelEnd.x - pixelStart.x;
        var deltaY = pixelEnd.y - pixelStart.y;
        var radius = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
        
        //create our circle    
        polyLine = createCircle(pixelStart, radius,"#ff0000", 10, 50);
        currentSearchRadius = polyLine;
        //add it to our map
		map.addOverlay(polyLine);
		
		//find our radius in kilometers
		radiusText = (startDrag.distanceFrom(point) / 1000).toString();
		decimalPointIndex = radiusText.indexOf(".");
		radiusText = radiusText.substring(0, decimalPointIndex + 3) + "km";
		
		//find the point between the center of the search and the outer right radius - simply add on radius / 2 to our search center's x value
		var overlayPositionPixels = new GPoint(pixelStart.x + (radius / 2), pixelStart.y);
		var distanceOverlay = new DistanceOverlay(radiusText, map.fromDivPixelToLatLng(overlayPositionPixels));
		//add it to our map
		map.addOverlay(distanceOverlay);
    }
}



function InitializeGUIProxySearch() {
    GEvent.addListener(map, "mousemove", function(point) {
            HandleGMapMouseMove(point);
        }
    );
    GEvent.addListener(map, "click", function(overlay,  point) {
            HandleGMapClick(point);
        }
    );
}


function InitializeBrowseMode() {
    GEvent.addListener(map, "dragend", Browse);
    GEvent.addListener(map, "zoomend", Browse);
}


function createCircle(center, radius, color, thickness, opacity) {
	//values are passed in in pixel space within the div
	var circleQuality = 10;
	var M = Math.PI / 180;
	//Init Point Array
	//Loop through all degrees from 0 to 360
	var points = new Array();
	for(var i=0; i<360; i+=circleQuality){
		var pixelPoint = new GPoint(
			center.x + (radius * Math.sin(i * M)),
			center.y + (radius * Math.cos(i * M))
			);
		var longLatPoint = map.fromDivPixelToLatLng(pixelPoint);
		points.push(longLatPoint);
	}
	points.push(points[0]);	// close the circle
	var p = new GPolygon(points, "#000000", 5, 0.25, color, 0.25)
	return p;
}



//class DistanceOverlay
function DistanceOverlay(text, latLong, opt_textClass, opt_textColor) {
  this.color_ = opt_textColor || "#000000";
  this.text_class_ = opt_textClass || "";
  this.text_ = text;
  this.latLong_ = latLong;
}

DistanceOverlay.prototype = new GOverlay();

// Creates the DIV representing this distance overlay.
DistanceOverlay.prototype.initialize = function(map) {
  // Create the DIV representing our rectangle
  var div = document.createElement("div");
  div.style.position = "absolute";
  div.innerHTML = "<span class=\"" + this.text_class + "\" style=\"color: " + this.color_ + "\">" + this.text_ + "</span>";
  // Our rectangle is flat against the map, so we add our selves to the
  // MAP_PANE pane, which is at the same z-index as the map itself (i.e.,
  // below the marker shadows)
  map.getPane(G_MAP_MAP_PANE).appendChild(div);
  this.map_ = map;
  this.div_ = div;
}

DistanceOverlay.prototype.remove = function() {
  this.div_.parentNode.removeChild(this.div_);
}

DistanceOverlay.prototype.copy = function() {
  return new DistanceOverlay(this.text_, this.text_class_, this.color_);
}

DistanceOverlay.prototype.redraw = function(force) {

  // We only need to redraw if the coordinate system has changed
  if (!force) return;
  
  position = this.map_.fromLatLngToDivPixel(this.latLong_);
  
  // Now position our DIV based on the DIV coordinates of our bounds
  this.div_.style.left = position.x + "px";
  this.div_.style.top = position.y + "px";
}

//class distance overlay
function DistanceOverlay(text, latLong, opt_textClass, opt_textColor) {
  this.color_ = opt_textColor || "#000000";
  this.text_class_ = opt_textClass || "";
  this.text_ = text;
  this.latLong_ = latLong;
}

DistanceOverlay.prototype = new GOverlay();

// Creates the DIV representing this distance overlay.
DistanceOverlay.prototype.initialize = function(map) {
  // Create the DIV representing our rectangle
  var div = document.createElement("div");
  div.style.position = "absolute";
  div.innerHTML = "<span class=\"" + this.text_class + "\" style=\"color: " + this.color_ + "\">" + this.text_ + "</span>";
  // Our rectangle is flat against the map, so we add our selves to the
  // MAP_PANE pane, which is at the same z-index as the map itself (i.e.,
  // below the marker shadows)
  map.getPane(G_MAP_MAP_PANE).appendChild(div);
  this.map_ = map;
  this.div_ = div;
}

DistanceOverlay.prototype.remove = function() {
  this.div_.parentNode.removeChild(this.div_);
}

DistanceOverlay.prototype.copy = function() {
  return new DistanceOverlay(this.text_, this.text_class_, this.color_);
}

DistanceOverlay.prototype.redraw = function(force) {

  // We only need to redraw if the coordinate system has changed
  if (!force) return;
  
  position = this.map_.fromLatLngToDivPixel(this.latLong_);
  
  // Now position our DIV based on the DIV coordinates of our bounds
  this.div_.style.left = position.x + "px";
  this.div_.style.top = position.y + "px";
}


/**
 * Class MarkerManager
 * Adds and removes markers from a google map based on the pixel resolution
 * of the current zoom level.
 */
function GoogleMarkerManager(gmap, multipleItemsImageUrl) {
	this.map = gmap;
	this.markers = [];
	this.managerPoints = [];
	this.groupedMarkers = [];
	this.pixelsPerSingleMarker = 10;
	this.pixelBoundsLatLng = this.getPixelBounds();
	this.multipleItemsImage = multipleItemsImageUrl;
	this.infoWindowOpen = false;
	this.visiblePointBounds = new GLatLngBounds();
	var me = this;
	GEvent.addListener(this.map, "zoomend", function(oldLevel, newLevel) {
		// update our pixel resolution
		me.pixelBoundsLatLng = me.getPixelBounds();
		me.resetAssignAllMarkers();
    });
	GEvent.addListener(this.map, "moveend", function() {
        if (!me.infoWindowOpen) {
            me.resetAssignAllMarkers();
        }
    });
    GEvent.addListener(this.map, "infowindowopen", function() {
        me.infoWindowOpen = true;
    });
    GEvent.addListener(this.map, "infowindowclose", function() {
        me.infoWindowOpen = false;
        me.resetAssignAllMarkers();
    });
}
/**
 * Adds a marker to the MarkerManager.  Marker can have an optional html parameter which will be 
 * concatinated with all the other markers within the pixel space when showInfoWindow is called.  
 * Marker must 
 * @param {Object} marker
 */
GoogleMarkerManager.prototype.add = function(marker) {
    var foundMarkerPoint = false;
    for (i = 0; i < this.managerPoints.length; i++) {
	    if (this.managerPoints[i].containsLatLng(marker.getLatLng())) {
		    this.managerPoints[i].addMarker(marker);
		    foundMarkerPoint = true;
	    }
    }
    if (!foundMarkerPoint) {
	    var managerPoint = new ManagerPoint(marker, this.pixelBoundsLatLng.lat() / 2, this.pixelBoundsLatLng.lng() / 2, this);
	    this.managerPoints.push(managerPoint);
	    this.managerPoints.isResultImage = marker.isResultImage;
    }
    
    this.markers.push(marker);
}

GoogleMarkerManager.prototype.addWithHtml = function(html, position, image) {
	var icon = new GIcon(G_DEFAULT_ICON);
	icon.image = image;
    icon.iconSize = new GSize(32,32);
    icon.shadowSize = new GSize(59,32);
	
	var marker = new GMarker(position, icon);
	marker.html = html;
	marker.singleImage = image;
	marker.isResultImage = image != '/resources/localisation/images/grey.png';
	this.add(marker);
}

GoogleMarkerManager.prototype.getPixelBounds = function() {
	var min = this.map.fromDivPixelToLatLng(new GPoint(0, this.map.getSize().height / 2));
	var max = this.map.fromDivPixelToLatLng(new GPoint(this.pixelsPerSingleMarker, this.pixelsPerSingleMarker));
	var deltaLat = max.lat() - min.lat();
	var deltaLng = max.lng() - min.lng();
	return new GLatLng(Math.sqrt(deltaLat * deltaLat), Math.sqrt(deltaLng * deltaLng));
}

GoogleMarkerManager.prototype.resortMarkersAfterMove = function() {
	if (!this.infoWindowOpen) {
	    var mapBounds = this.map.getBounds();
	    for (i = 0; i < this.managerPoints.length; i++) {
		    var managerPoint = this.managerPoints[i];
		    if (mapBounds.contains(managerPoint.marker.getLatLng())) {
			    managerPoint.setVisibility(true);
		    } else {
			    managerPoint.setVisibility(false);
		    }
	    }
	}
}

GoogleMarkerManager.prototype.resetAssignAllMarkers = function(){
	this.map.clearOverlays();
	this.visiblePointBounds = new GLatLngBounds();
	this.managerPoints = [];
	var mapBounds = this.map.getBounds();
	var pointsToWorryAbout = [];
	for (p = 0; p < this.markers.length; p++) {
	    if (mapBounds.containsLatLng(this.markers[p].getLatLng())) {
	        pointsToWorryAbout.push(this.markers[p]);
	    }
	}
	for (j = 0; j < pointsToWorryAbout.length; j++) {
		var marker = pointsToWorryAbout[j];
		var foundMarkerPoint = false;
		this.visiblePointBounds.extend(pointsToWorryAbout[j].getLatLng()); 
		for (i = 0; i < this.managerPoints.length; i++) {
			if (this.managerPoints[i].containsLatLng(marker.getLatLng())) {
				this.managerPoints[i].addMarker(marker);
				foundMarkerPoint = true;
			}
			if (this.map.getBounds().contains(this.managerPoints[i].marker.getLatLng())) {
		        this.managerPoints[i].setVisibility(true);
		    } else {
				this.managerPoints[i].setVisibility(false); 
			}
		}
		if (!foundMarkerPoint) {
			var managerPoint = new ManagerPoint(marker, this.pixelBoundsLatLng.lat() / 2, this.pixelBoundsLatLng.lng() / 2, this);
			this.managerPoints.push(managerPoint);
			if (this.map.getBounds().contains(marker.getLatLng())) {
			    this.managerPoints[i].setVisibility(true);
			} else {
			    this.managerPoints[i].setVisibility(false); 
		    }
		}
	}
}

GoogleMarkerManager.prototype.getMultipleItemsImage = function() {
    return this.multipleItemsImage;
}


/**
 * Class ManagerPoint
 * @param {GMarker} marker
 */
function ManagerPoint(marker, halfLat, halfLng, markerManager) {
	var me = this;
	this.marker = marker;
	this.associatedPoints = [];
	this.resetBounds(halfLat, halfLng);
	this.markerManager = markerManager;
	this.visible = true;
	this.containsResultImage = marker.isResultImage;
	GEvent.addListener(marker, "click", function() {
    	markerManager.map.openInfoWindowHtml(me.marker.getLatLng(), me.generateHTML());
    });
	if (markerManager.map.getBounds().intersects(this.bounds)) {
		markerManager.map.addOverlay(this.marker);
	} else {
		this.visible = false;
	}
	
}

ManagerPoint.prototype.resetBounds = function(halfLat, halfLng, imageName) {
	var min = new GLatLng(this.marker.getLatLng().lat() - halfLat, this.marker.getLatLng().lng() - halfLng);
	var max = new GLatLng(this.marker.getLatLng().lat() + halfLat, this.marker.getLatLng().lng() + halfLng);
	this.bounds = new GLatLngBounds(min, max);
}

ManagerPoint.prototype.containsLatLng = function(latLng) {
	return this.bounds.containsLatLng(latLng);
}

ManagerPoint.prototype.addMarker = function(marker) {
	if (marker.isResultImage) {
	    this.containsResultImage = true;
	}
	this.associatedPoints.push(marker);
}

ManagerPoint.prototype.generateHTML = function() {
	var height = '100px';
	if (this.associatedPoints.length > 1) {
		height='200px';
	}
	var html = '<div style="width: 462px; height: ' + height + '; overflow: auto;"><table><tr><td><img src=\'' + this.marker.singleImage + '\' /></td><td>' + this.marker.html + '</td></tr>';
	for (i = 0; i < this.associatedPoints.length; i++) {
		html += '<tr><td><img src=\'' + this.associatedPoints[i].singleImage + '\' /></td><td>' + this.associatedPoints[i].html + '</td></tr>';
	}
	return html + '</table></div>';
}

ManagerPoint.prototype.getBounds = function() {
	return this.bounds;
}

ManagerPoint.prototype.isVisible = function() {
	return this.visible;
}

ManagerPoint.prototype.setVisibility = function(visible) {
	if (visible) {
	    if (!this.isVisible()) {
		    this.markerManager.map.addOverlay(this.marker);
		}
		if (this.associatedPoints.length > 0) {
		    if (this.containsResultImage) {
		        this.marker.setImage('/resources/localisation/images/plus.png');
		    } else {
		        this.marker.setImage('/resources/localisation/images/greyplus.png');
		    }
	    } else {
		    this.marker.setImage(this.marker.singleImage);
		}
	} else {
	    if (this.isVisible()) {
		    this.markerManager.map.removeOverlay(this.marker);
		}
	}
	this.visible = visible;
}
