﻿// JScript File
/* Factory Object for manufacturing customised Markers */
/******************************************/
/* The code to create icon images utilises URLs described in the following references:
 * 
 * http://gmaps-utility-library.googlecode.com/svn/trunk/mapiconmaker/1.1/docs/examples.html
 * http://gmapicons.googlepages.com/
 * http://groups.google.com/group/google-chart-api/web/chart-types-for-map-pins
 */
 
function RSPBMarkerFactory(opts) {
	// Fudge to let inner functions access Member variables
	var that = this;
	// Not all options are used in all cases, but set up defaults anyway
	var width = opts.width || 32;
	var height = opts.height || 32;
	var primaryColour = opts.primaryColour || "#00ff00";
	var strokeColour = opts.strokeColour || "#000000";
	var shadowColour = opts.shadowColour || "#000000";
	var cornerColour = opts.cornerColour || "#ffffff";
	var labelColour = opts.labelColour || "#000000";
	var starColour = opts.starColour || "#ffff00";
	var labelSize = opts.labelSize || 0;				// 0 = Fit to size of icon
	var presetLabel = opts.presetLabel;					// default is null
	var iconUrl = opts.iconUrl || "http://maps.google.com/mapfiles/arrow.png";
	var shadowUrl = opts.shadowUrl || "http://maps.google.com/mapfiles/arrowshadow.png";
	var type = opts.type || "default";					// "circle", "roundrect", "flatpin", "pin", "pinstar", "url", "default"
	
	// Constructed values, used as parameters in actually making a Marker
	this.labelType = opts.labelType || "rollover";		// Options are "image" (i.e. within the image) or "rollover" or "both"
	this.markerOptions = null;		// Mandatory in all cases
	this.getMarkerImage = null;		// Mandatory in all cases
	var markerImage;				// When Label is not included in URL
	var iconUrlA;					// If Label is to be added to the URL
	var iconUrlB;					// If Label is to be added to the URL
	var iconSize;					// If Label is to be added to the URL
	var iconOrigin;					// If Label is to be added to the URL
	var iconAnchor;					// If Label is to be added to the URL
	
	// Prepare Parameters needed when it comes to actually making a Marker
	if ((type == "circle") || (type == "roundrect")) createFlatOptions();
	else if (type == "flatpin") createFlatPinOptions();
	else if ((type == "pin") || (type == "pinstar")) createLabeledPinOptions();
	else if (type == "url") createUrlOptions();
	else createDefaultOptions();
	
	/* Make Marker according to the parameters set up in the constructor */
	this.makeMarker = function (opts) {
		var mLabel = escapeUserText(opts.label) || "";
		var mLatLng = new google.maps.LatLng(opts.lat, opts.lng);

		var theMarker = new google.maps.Marker(this.markerOptions);
		// getMarkerImage() is preset to the correct behaviour according to the type of Factory
		theMarker.setIcon(this.getMarkerImage(mLabel));
		if ((this.labelType == "rollover") || (this.labelType == "both")) theMarker.setTitle(mLabel);
		theMarker.setPosition(mLatLng);
		
		return theMarker;		
	}
	
	/* The two possible functions to be set up as this.getMarkerImage */
	function getMarkerImageSimple() {return markerImage;}
	
	function getMarkerImageLabel(label) {
		var iconUrl = iconUrlA + label + iconUrlB;
		return new google.maps.MarkerImage(iconUrl, iconSize, iconOrigin, iconAnchor);
	}
	
	/***********************************************************************************/
	/* Routines called by the constructor to set up the options for the particular type of Factory being created. */
	/* Flat Circle or roundRectangle - with or without label 
	 *   Supported options are: type, width, height, primaryColour, shadowColour, labelType, labelColour, LabelSize.
	 */
	function createFlatOptions() {
		iconSize = new google.maps.Size(width, height);
		iconOrigin = new google.maps.Point(0,0);
		iconAnchor = new google.maps.Point(width/2, height/2);
		
		var typeCode = (type == "circle") ? "it" : "itr";
		var baseUrl = "http://chart.apis.google.com/chart?cht=" + typeCode;
		var tailUrl = "&chf=bg,s,00000000&ext=.png";
		var iconUrl = baseUrl + "&chs=" + width + "x" + height + "&chco=" + primaryColour.replace("#", "") + ",000000ff," + shadowColour.replace("#", "") + "01";
		if ((that.labelType == "image") || (that.labelType == "both")) {
			iconUrlA = iconUrl + "&chl=";
			iconUrlB = "&chx=" + labelColour.replace("#", "") + "," + labelSize + tailUrl;
			that.getMarkerImage = getMarkerImageLabel;
		}
		else {
			iconUrl += tailUrl;
			markerImage = new google.maps.MarkerImage(iconUrl, iconSize, iconOrigin, iconAnchor);
			that.getMarkerImage = getMarkerImageSimple;			
		}
	
		// Only need Shape defined if is to be clickable, or rollover text
		var markerShape;
		if (type == "roundrect") {
			var markerShape = [0, 0, width, 0, width, height, 0, height];
		} else {
			var polyNumSides = 8;
			var polySideLength = 360/polyNumSides;
			var polyRadius = Math.min(width, height)/2;
			var markerShape = new Array();
			for (var a = 0; a<(polyNumSides+1); a++) {
				var aRad = polySideLength*a*(Math.PI/180);
				var pixelX = polyRadius + polyRadius * Math.cos(aRad);
				var pixelY = polyRadius + polyRadius * Math.sin(aRad);
				markerShape.push(parseInt(pixelX), parseInt(pixelY));
			}
		}
		that.markerOptions = {shape: markerShape, flat:true};
	};
	
	/* Pin Marker with variable size, and colour.  
	*   Supported options are: type, width, height, cornerColour, primaryColour, strokeColour.
	*/
	function createFlatPinOptions() {
		iconSize = new google.maps.Size(width, height);
		iconOrigin = new google.maps.Point(0,0);
		iconAnchor = new google.maps.Point(width/2, height);

		var baseUrl = "http://chart.apis.google.com/chart?cht=mm";
		var iconUrl = baseUrl + "&chs=" + width + "x" + height + "&chco=" + cornerColour.replace("#", "") + "," + primaryColour.replace("#", "") + "," + strokeColour.replace("#", "") + "&ext=.png";

		markerImage = new google.maps.MarkerImage(iconUrl, iconSize, iconOrigin, iconAnchor);
		that.getMarkerImage = getMarkerImageSimple;			

		var markerShape;
		markerShape = [
		    width/2, height,
		    (7/16)*width, (5/8)*height,
		    (5/16)*width, (7/16)*height,
		    (7/32)*width, (5/16)*height,
		    (5/16)*width, (1/8)*height,
		    (1/2)*width, 0,
		    (11/16)*width, (1/8)*height,
		    (25/32)*width, (5/16)*height,
		    (11/16)*width, (7/16)*height,
		    (9/16)*width, (5/8)*height
		];
		for (var i = 0; i < markerShape.length; i++) {
		    markerShape[i] = parseInt(markerShape[i]);
		}
		that.markerOptions = {shape: markerShape, flat:true};
	};
	
	/* Labelled Pin, with optional Star */
	/* Uses an Icon URL from a different source, since the one from MapIconMaker did not work in v£ API 
	*   Supported options are: type, primaryColour, labelColour, starColour, presetLabel.
	 */

	function createLabeledPinOptions() {
		iconSize = new google.maps.Size(22, 38);
		iconOrigin = new google.maps.Point(0, 0);
		iconAnchor = new google.maps.Point(11, 38);
		
		var typeCode1 = (type == "pinstar") ? "d_map_xpin_letter" : "d_map_pin_letter";
  		var typeCode2 = (type == "pinstar") ? "pin_star|" : "";
		
		if (presetLabel) {
			iconUrl = "http://www.google.com/chart?chst=" + typeCode1 + "&chld=" + typeCode2 +  escapeUserText(presetLabel) + "|" + primaryColour.replace("#", "") + "|" + labelColour.replace("#", "");
			if (type == "pinstar") iconUrl += "|" + starColour.replace("#", ""); 
			markerImage = new google.maps.MarkerImage(iconUrl, iconSize, iconOrigin, iconAnchor);
			that.getMarkerImage = getMarkerImageSimple;			
		}
		else {
			iconUrlA = "http://www.google.com/chart?chst=" + typeCode1 + "&chld=" + typeCode2;
			iconUrlB = "|" + primaryColour.replace("#", "") + "|" + labelColour.replace("#", "");
			if (type == "pinstar") iconUrlB += "|" + starColour.replace("#", ""); 
			that.getMarkerImage = getMarkerImageLabel;
		}
		
		var markerShape;
		markerShape = [0, 0, 22, 0, 22, 38, 0, 38];
		var shadowImage = new google.maps.MarkerImage(	
			"http://www.google.com/chart?chst=d_map_pin_shadow", 
			new google.maps.Size(35, 38),
			new google.maps.Point(0, 0),		//Origin
			new google.maps.Point(11, 38));		//Anchor
		that.markerOptions = {shape: markerShape, shadow: shadowImage};
	};

	/* Use the supplied image URL */
	/*   Supported options are: type, iconUrl, shadowUrl, width, height.  */
	function createUrlOptions() {
		markerImage = new google.maps.MarkerImage(iconUrl,	
			new google.maps.Size(width, height),
			new google.maps.Point(0, 0),					//Origin
			new google.maps.Point(width/2, height));		//Anchor (guess)
			
		var shadowImage;
		if (shadowUrl) {
			shadowImage = new google.maps.MarkerImage(shadowUrl,	
				new google.maps.Size(width*1.6, height),
				new google.maps.Point(0, 0),					//Origin
				new google.maps.Point(width/2, height));		//Anchor (guess)		
		}
		
		var markerShape;
		markerShape = [0, 0, width, 0, width, height, 0, height];
		that.markerOptions = {shadow: shadowImage, shape: markerShape};
		that.getMarkerImage = getMarkerImageSimple;
	};
	
	/* Google default Marker - Omit all parameters */
	function createDefaultOptions() {
		that.getMarkerImage = getMarkerImageSimple;
	};

	
	/*
	 * Utility function for doing special chart API escaping first,
	 *  and then typical URL escaping. Must be applied to user-supplied text.
	 */
	function escapeUserText(text) {
	  if (text === undefined) {
		return null;
	  }
	  text = text.replace(/@/, "@@");
	  text = text.replace(/\\/, "@\\");
	  text = text.replace(/'/, "@'");
	  text = text.replace(/\[/, "@[");
	  text = text.replace(/\]/, "@]");
      return text;
	  // return encodeURIComponent(text);   // Strings are protected on Server side - don't need this, and it upsets tooltips.
	};

}

