﻿general.namespace('SW.Markers');

(function () {

    var Markers = SW.Markers;
    
    Markers.DEGREES_PER_SECTOR = 2;
	Markers.NUM_HORIZONTAL_SECTORS  = Math.ceil(360 / Markers.DEGREES_PER_SECTOR);
	Markers.NUM_VERTICAL_SECTORS = Math.ceil(180 / Markers.DEGREES_PER_SECTOR);
			
	/**
	 * dataTypeId enum - TODO internationalize
	 */
	Markers.DataType = {
		Buoy : { 
			"id"        : 1013, 
			"singular"  : "Buoy", 
			"plural"    : "Buoys", 
			"icon"      : "/assets/images/map-marker-buoy.png",
			"groupIcon" : "/assets/images/map-marker-buoy-group.png",
			"enumName"  : "Buoy",
			"clickHandler" : inspectorManager.displayBuoy
		},
		TideStation : {
			"id"        : 1016, 
			"singular"  : "Tide Station", 
			"plural"    : "Tide Stations", 
			"icon"      : "/assets/images/map-marker-tide.png",
			"groupIcon" : "/assets/images/map-marker-tide-group.png",
			"enumName"  : "TideStation",
			"clickHandler" : inspectorManager.displayTideStation
		},
		WeatherZone : { 
			"id"        : 1020, 
			"singular"  : "Weather Report", 
			"plural"    : "Weather Reports", 
			"icon"      : "/assets/images/map-marker-text.png",
			"groupIcon" : "/assets/images/map-marker-text-group.png",
			"enumName"  : "WeatherZone",
			"clickHandler" : inspectorManager.displayWeatherZone
		},
		SurfSpot : { 
			"id"        : 1021, 
			"singular"  : "Surf Spot", 
			"plural"    : "Surf Spots", 
			"icon"      : "/assets/images/map-marker-surf.png",
			"groupIcon" : "/assets/images/map-marker-surf-group.png",
			"enumName"  : "SurfSpot",
			"clickHandler" : inspectorManager.displaySurfSpot
		},
		VirtualBuoy : { 
			"id"        : 1022, 
			"singular"  : "Surf Probe", 
			"plural"    : "Surf Probes", 
			"icon"      : "/assets/images/XXX.png",
			"groupIcon" : "/assets/images/map-marker-XXX-group.png",
			"enumName"  : "VirtualBuoy",
			"clickHandler" : inspectorManager.displayVirtualBuoy
		},
		ForecasterReport : { 
			"id"        : 1025, 
			"singular"  : "Report/Forecast", 
			"plural"    : "Reports/Forecasts", 
			"icon"      : "/assets/images/XXX.png",
			"groupIcon" : "/assets/images/map-marker-XXX-group.png",
			"enumName"  : "ForecasterReport",
			"clickHandler" : null
		},
		PerspectiveView : { 
			"id"        : 1023, 
			"singular"  : "3D View", 
			"plural"    : "3D Views", 
			"icon"      : "/assets/images/map-marker-3d.png",
			"groupIcon" : "/assets/images/map-marker-3d-group.png",
			"enumName"  : "PerspectiveView",
			"clickHandler" : null
		}
	};    
	
	
	Markers.DATA_TYPES = [];
	Markers.DATA_TYPES_BY_ID = {};
	for (var type in Markers.DataType) {
		var dataType = Markers.DataType[type];
		Markers.DATA_TYPES_BY_ID[dataType.id] = dataType;
		Markers.DATA_TYPES.push(type);
	}
	
	
	/* registered as 'click' to each group marker */
	Markers.onGroupMarkerClick = function () {
	    // need to center and zoom twice to adjust the lat to the true visual center
	    var oldZoom = SWMap.map.getZoom();
	    handlers.setZoomEndHandler('DUMMY');
	    SWMap.map.centerAndZoomOnBounds(this.zoomBounds);
        var newZoom = SWMap.map.getZoom();
        handlers.onZoomEnd(oldZoom, newZoom);
	};
	
	
	/* registered as 'click' to each marker */
	Markers.onSingleMarkerClick = function () {
	    this.clickHandler(this.pointId, this.name);  // 'this' should be the marker
	};
	
	if (typeof GMap !== 'undefined') {
	    var BASE_ICON = new GIcon(G_DEFAULT_ICON);
	    BASE_ICON.iconSize = new GSize(28, 28);
	    BASE_ICON.iconAnchor = new GPoint(14, 28);
	    BASE_ICON.shadow = '/assets/images/map-marker-shadow.png';
	    BASE_ICON.shadowSize = new GSize(35, 32);
    	
	    var ICONS = {
		    Buoy: new GIcon(BASE_ICON, Markers.DataType.Buoy.icon),
		    SurfSpot: new GIcon(BASE_ICON, Markers.DataType.SurfSpot.icon),
		    WeatherZone: new GIcon(BASE_ICON, Markers.DataType.WeatherZone.icon),
		    TideStation: new GIcon(BASE_ICON, Markers.DataType.TideStation.icon),
		    PerspectiveView: new GIcon(BASE_ICON, Markers.DataType.PerspectiveView.icon), 
		    none: G_DEFAULT_ICON
	    };
	    
	    var BASE_GROUP_ICON = new GIcon(G_DEFAULT_ICON);
	    BASE_GROUP_ICON.iconSize = new GSize(17, 28);
	    BASE_GROUP_ICON.iconAnchor = new GPoint(8, 26);
	    BASE_GROUP_ICON.shadow = '/assets/images/map-marker-shadow-group.png';
	    BASE_GROUP_ICON.shadowSize = new GSize(31, 31);
	    
	    var GROUP_ICONS = {
		    Buoy: new GIcon(BASE_GROUP_ICON, Markers.DataType.Buoy.groupIcon),
		    SurfSpot: new GIcon(BASE_GROUP_ICON, Markers.DataType.SurfSpot.groupIcon),
		    WeatherZone: new GIcon(BASE_GROUP_ICON, Markers.DataType.WeatherZone.groupIcon),
		    TideStation: new GIcon(BASE_GROUP_ICON, Markers.DataType.TideStation.groupIcon),
		    PerspectiveView: new GIcon(BASE_GROUP_ICON, Markers.DataType.PerspectiveView.groupIcon), 
		    none: G_DEFAULT_ICON
	    };
    	
	}
	
	/* Each marker gets its own unique integer id so markers can 
	 * be easily hashed.
	*/
	var markerId = 0; 
	Markers.getMarkerId = function () {
		++markerId;
		return markerId;
	}
	
	Markers.requestsPending = 0;
	
	/* Create and return a marker representing an individual point.
	 */
	Markers.createSingleMarker = function (point, markerType) {
		var marker = new GMarker(
			new GLatLng(point.lat, point.lng),
			{
				title: point.name, 
				icon: ICONS[markerType]
			}
		);
		
		marker.isGroup = false;
		marker.hashId = Markers.getMarkerId();
		marker.pointId = point.id;
		marker.name = point.name;
		
		marker.clickHandler = Markers.DATA_TYPES_BY_ID[point.dataTypeId].clickHandler;
		
		GEvent.addListener(marker, "click", Markers.onSingleMarkerClick);
		
		return marker;
	};

		
	/* Create and return a marker representing multiple points.
	 */              
	Markers.createGroupMarker = function (points, markerType) {
		
		// 'count' is how many points this group represents
		/*
		var count = 0;
		for (var i in points) {
			count += points[i].count;
		}
		*/
		
		var marker = new GMarker(
			mapGeneral.averageOfPoints(points),
			{
				title: 'Multiple points here. Click to zoom.',
				icon: GROUP_ICONS[markerType]
			}
		);
		
		if (points.length > 1) {
		    marker.zoomBounds = mapGeneral.boundsOfPoints_naive(points).resizeByFactor(1.3);   // 'this' should be the marker; resize so that markers aren't too close to the edge of map 
		}
		else { // points.length == 1 
		    // create bounds of 1 degree margin around the point (not ideal, but reasonable for most cases)
		    marker.zoomBounds = mapGeneral.boundsAroundPoint(points[0].lat, points[0].lng, 1);		    
		}
		
		marker.isGroup = true;
		marker.hashId = Markers.getMarkerId();
		
		GEvent.addListener(marker, "click", Markers.onGroupMarkerClick);
		
		return marker;
	};
	
	
	/* Put points of bounds into sections, returning the points in lists hashed by section. 
	 */
	Markers.createPointHash = function (points, bounds, numLatSections, numLngSections) {
	
		var boundsCoords = bounds.getCoords();
		var latOffset = -boundsCoords.S;
		var lngOffset = -boundsCoords.W;
		
		var boundsDimensions = bounds.toSpan();
		var sectionLatSize = boundsDimensions.lat() / numLatSections;
		var sectionLngSize = boundsDimensions.lng() / numLngSections;
		
		var pointHash = {};
		for (var i in points) {
			var point = points[i];

			var latSection = Math.floor((point.lat + latOffset) / sectionLatSize);
			if (latSection === numLatSections) {
				latSection--;
			}    
			
			var lngSection = Math.floor((point.lng + lngOffset) / sectionLngSize);
			if (lngSection === numLngSections) {
				lngSection--;
			}
			
			var sectionId = latSection + '-' + lngSection; // using numeric id cheaper than string id (value of 100 works fine as long as lngSection is always less than 3 digits)
			
			if (pointHash[sectionId]) {
				pointHash[sectionId].push(point);
			}
			else {
				pointHash[sectionId] = [point];
			}
		}
		
		return pointHash;
	};
	
	
	/** Return list of markers that corresponds to the points. The bounds is divied up into sections
	 * such that multiple points in one section become just one group marker. Only a point that
	 * is alone in its section becomes an individual marker.
	 */
	Markers.createMarkers = function (points, bounds, markerType, numLatSections, numLngSections) {
		numLngSections = numLngSections || numLatSections;
	
		var pointsBySectionId = Markers.createPointHash(
			points,
			bounds,
			numLatSections, 
			numLngSections
		);
		
		// add points of each section 
		var newMarkers = [];
		for (var sectionId in pointsBySectionId) {
			var sectorPoints = pointsBySectionId[sectionId];
			
			var marker;
			if (sectorPoints.length > 1 || sectorPoints[0].count > 1) { // if more than one point in sector or if the single point represents multiple points
				marker = Markers.createGroupMarker(sectorPoints, markerType);
			}
			else { // length === 1
				marker = Markers.createSingleMarker(sectorPoints[0], markerType);
			}
			newMarkers.push(marker);
		}
		
		return newMarkers;
	};

})();