﻿var Mapifies;
var toggleDropDown = true;

if (!Mapifies) Mapifies = {};

/**
 * The main object that holds the maps
 */
Mapifies.MapObjects = {};

google.load("maps", "2");

Mapifies.MapObjects.Set = function ( element, options ) {
	var mapName = jQuery(element).attr('id');
	var thisMap = new google.maps.Map2(element);
	Mapifies.MapObjects[mapName] = thisMap;
	Mapifies.MapObjects[mapName].Options = options;
	return Mapifies.MapObjects[mapName];
};

Mapifies.MapObjects.Append = function ( element, description, appending ) {
	var mapName = jQuery(element).attr('id');
	Mapifies.MapObjects[mapName][description] = appending;
};

Mapifies.MapObjects.Get = function ( element ) {
	return Mapifies.MapObjects[jQuery(element).attr('id')];
};

Mapifies.Init = function ( element, options, callback ) {
	
	function defaults() {
		return {
			// Initial type of map to display
			'language': 'en',
			// Options: "map", "sat", "hybrid"
			'mapType': 'map',
			// Initial map center
			'mapCenter': [55.958858,-3.162302],
			// Initial map size
			'mapDimensions': [400, 400],
			// Initial zoom level
			'mapZoom': 12,
			// Initial map control size
			// Options: "large", "small", "none"
			'mapControlSize': 'small',
			// Initialise type of map control
			'mapEnableType': false,
			// Initialise small map overview
			'mapEnableOverview': false,
			// Enable map dragging when left button held down
			'mapEnableDragging': true,
			// Enable map info windows
			'mapEnableInfoWindows': true,
			// Enable double click zooming
			'mapEnableDoubleClickZoom': false,
			// Enable zooming with scroll wheel
			'mapEnableScrollZoom': false,
			// Enable smooth zoom
			'mapEnableSmoothZoom': false,
			// Enable Google Bar
			'mapEnableGoogleBar': false,
			// Enables scale bar
			'mapEnableScaleControl': false,
			//Debug Mode
			'debugMode': false,
			//  Initial To Address for directions
			'initToAddress': ''
		};
	};
	options = jQuery.extend(defaults(), options);
	
	if (google.maps.BrowserIsCompatible()) {
			
		var thisMap = Mapifies.MapObjects.Set(element, options);
		var mapType = Mapifies.GetMapType(options.mapType);
		Mapifies.CreateMarkerManager(element, {}, null);
		Mapifies.MapObjects.Append(element, "ToAddress", options.initToAddress);
		Mapifies.MapObjects.Append(element, "FromAddress", '');
		thisMap.setCenter(new google.maps.LatLng(options.mapCenter[0], options.mapCenter[1]), options.mapZoom, mapType);
		
		// Attach a controller to the map view
		// Will attach a large or small.  If any other value passed (i.e. "none") it is ignored
		switch (options.mapControlSize) {
			case "small":
				thisMap.addControl(new google.maps.SmallMapControl());
				break;
			case "large":
				thisMap.addControl(new google.maps.LargeMapControl());
				break;
		};
		// Type of map Control (Map,Sat,Hyb)
		if (options.mapEnableType) 
			thisMap.addControl(new google.maps.MapTypeControl()); // Off by default
		// Show the small overview map
		if (options.mapEnableOverview) 
			thisMap.addControl(new google.maps.OverviewMapControl());// Off by default
		// GMap2 Functions (in order of the docs for clarity)
		// Enable a mouse-dragable map
		if (!options.mapEnableDragging) 
			thisMap.disableDragging(); // On by default
		// Enable Info Windows
		if (!options.mapEnableInfoWindows) 
			thisMap.disableInfoWindow(); // On by default
		// Enable double click zoom on the map
		if (options.mapEnableDoubleClickZoom) 
			thisMap.enableDoubleClickZoom(); // On by default
		// Enable scrollwheel on the map
		if (options.mapEnableScrollZoom) 
			thisMap.enableScrollWheelZoom(); //Off by default
		// Enable smooth zooming
		if (options.mapEnableSmoothZoom) 
			thisMap.enableContinuousZoom(); // Off by default
		// Enable Google Bar
		if (options.mapEnableGoogleBar) 
			thisMap.enableGoogleBar(); //Off by default
		// Enables Scale bar
		if (options.mapEnableScaleControl) 
			thisMap.addControl(new google.maps.ScaleControl());
		
		if (options.debugMode) 
			console.log(Mapifies);
		
		if (typeof callback == 'function') 
			return callback(element, options);
	} else {
		jQuery(element).text('Your browser does not support Google Maps.');
		return false;
	}
	return;
};

Mapifies.MoveTo = function ( element, options, callback ) {
		
	function defaults() {
		return {
			centerMethod: 'normal',
			mapType: null,
			mapCenter: [],
			mapZoom: null
		};
	};
	
	var thisMap = Mapifies.MapObjects.Get(element);
	options = jQuery.extend(defaults(), options);	
	
	if (options.mapType)
		var mapType = Mapifies.GetMapType(options.mapType);
	var point = new google.maps.LatLng(options.mapCenter[0], options.mapCenter[1]);
	switch (options.centerMethod) {
		case 'normal':
			thisMap.setCenter(point, options.mapZoom, mapType);
		break;
		case 'pan':
			thisMap.panTo(point);
		break;
	}
	if (typeof callback == 'function') return callback(point, options);
}
	
Mapifies.SavePosition = function( element, options, callback ) {
	var thisMap = Mapifies.MapObjects.Get(element);
	thisMap.savePosition();
	if (typeof callback == 'function') return callback();
};

Mapifies.GotoSavedPosition = function ( element, options, callback) {
	var thisMap = Mapifies.MapObjects.Get(element);
	thisMap.returnToSavedPosition();
	if (typeof callback == 'function') return callback();
};
	
Mapifies.CreateKeyboardHandler = function( element, options, callback ) {
	var thisMap = Mapifies.MapObjects.Get(element);
	var keyboardHandler = new google.maps.KeyboardHandler(thisMap);
	if (typeof callback == 'function') return callback(keyboardHandler);
};

Mapifies.GetMapType = function ( mapType ) {
	// Lets set our map type based on the options
	switch(mapType) {
		case "map":	// Normal Map
			mapType = G_NORMAL_MAP;
		break;
		case "sat":	// Satallite Imagery
			mapType = G_SATELLITE_MAP;
		break;
		case "hybrid":	//Hybrid Map
			mapType = G_HYBRID_MAP;
		break;
	};
	return mapType;
};

Mapifies.GetTravelMode = function ( travelMode ) {
	switch(travelMode) {
		case "driving":	
			travelMode = G_TRAVEL_MODE_DRIVING;
		break;
		case "walking":	
			travelMode = G_TRAVEL_MODE_WALKING;
		break;
	};
	return travelMode;
};

function createIcon (options) {
	
	function defaults() {
		return {
			iconImage: "",
			iconShadow: "",
			iconSize: [59, 50],
			iconShadowSize: null,
			iconAnchor: [29, 50],
			iconInfoWindowAnchor: [18, 6],
			iconPrintImage: "",
			iconMozPrintImage: "",
			iconPrintShadow: "",
			iconTransparent: ""
		};
	};
	
	options = jQuery.extend(defaults(), options);
	var icon = new google.maps.Icon();
		
	if(options.iconImage)
		icon.image = options.iconImage;
	if(options.iconShadow)
		icon.shadow = options.iconShadow;
	if(options.iconSize)
		icon.iconSize = new google.maps.Size(options.iconSize[0], options.iconSize[1]);
	if(options.iconShadowSize)
		icon.shadowSize = new google.maps.Size(options.iconShadowSize[0],options.iconShadowSize[1]);
	if(options.iconAnchor)
		icon.iconAnchor = new google.maps.Point(options.iconAnchor[0], options.iconAnchor[1]);
	if(options.iconInfoWindowAnchor)
		icon.infoWindowAnchor = new google.maps.Point(options.iconInfoWindowAnchor[0], options.iconInfoWindowAnchor[1]);
	return icon;
};

function getCenter ( element ) {
	var thisMap = Mapifies.MapObjects.Get(element);
	return thisMap.getCenter();
};
	
function getBounds(element){
	var thisMap = Mapifies.MapObjects.Get(element);
	return thisMap.getBounds();
};

Mapifies.SearchAddress = function( element, options, callback) {
	
	function defaults() {
		return {
			// what to return, "latlng" or "points"
			type: 'latlng',
			// Address to search for
			address: null,
			// Optional Cache to store Geocode Data (not implemented yet)
			cache: {},
			// Country code for localisation (not implemented yet)
			countryCode: 'uk'
		};
	};
	var thisMap = Mapifies.MapObjects.Get(element);
	options = jQuery.extend(defaults(), options);
			
	// Check to see if the Geocoder already exists in the object
	// or create a temporary locally scoped one.
	if (typeof thisMap.Geocoder == 'undefined') {
		var geocoder = new google.maps.ClientGeocoder;
	} else {
		var geocoder = thisMap.Geocoder;
	}
		
	// Geocode the address
	switch (options.type) {
		case 'latlng':
			geocoder.getLatLng(options.address, function(point){
				if (typeof callback == 'function') return callback(point, options);
			});
		break;
		case 'points':
			geocoder.getLocations(options.address, function(points){
				if (typeof callback == 'function') return callback(points, options);
			});
		break;
	};
	
	return;
};
	
Mapifies.SearchDirections = function( element, options, callback) {
	function defaults() {
		return {
			// From address
			'directions': '',
			// Optional panel to show text directions
			'panel': "",
			//The locale to use for the directions result.
			'locale': 'en_GB',
			//The mode of travel, such as driving (default) or walking
			'travelMode': 'driving',
			// Option to avoid highways
			'avoidHighways': false,
			// Get polyline
			'getPolyline': true,
			// Get directions
			'getSteps': true,
			// Preserve Viewport
			'preserveViewport' : false
		};
	};
	var thisMap = Mapifies.MapObjects.Get(element);
	options = jQuery.extend(defaults(), options);
	
	var queryOptions = {
		'locale': options.locale,
		'travelMode': options.travelMode,
		'avoidHighways': options.avoidHighways,
		'getPolyline': options.getPolyline,
		'getSteps': options.getSteps,
		'preserveViewport' : options.preserveViewport
	};
	
	var panel = $(options.panel).get(0);
	var directions = new google.maps.Directions(thisMap, panel);
	
	google.maps.Event.addListener(directions, "load", onLoad);
    google.maps.Event.addListener(directions, "error", onError);
	
	directions.load(options.directions, queryOptions);
	
	function onLoad() {
		if (typeof callback == 'function') return callback(directions, options);	
	}
	
	function onError() {
		if (typeof callback == 'function') return callback(directions, options);	
	}
	
	return;
};

function SearchDirectionsCode(code){
	switch (code) {
		case G_GEO_SUCCESS:
			return {'code':G_GEO_SUCCESS,'success':true,'message':'Success'};
		case G_GEO_UNKNOWN_ADDRESS:
			return {'code' : G_GEO_UNKNOWN_ADDRESS, 'success' : false, 'message' : 'No corresponding geographic location could be found for one of the specified addresses. This may be due to the fact that the address is relatively new, or it may be incorrect'};
			break;
		case G_GEO_SERVER_ERROR:
			return {'code' : G_GEO_UNKNOWN_ADDRESS, 'success' : false, 'message' : 'A geocoding or directions request could not be successfully processed, yet the exact reason for the failure is not known.'};
			break;
		case G_GEO_MISSING_QUERY:
			return {'code' : G_GEO_UNKNOWN_ADDRESS, 'success' : false, 'message' : 'The HTTP q parameter was either missing or had no value. For geocoder requests, this means that an empty address was specified as input. For directions requests, this means that no query was specified in the input.'};
			break;
		case G_GEO_BAD_KEY:
			return {'code' : G_GEO_UNKNOWN_ADDRESS, 'success' : false, 'message' : 'The given key is either invalid or does not match the domain for which it was given.'};
			break;
		case G_GEO_BAD_REQUEST:
			return {'code' : G_GEO_UNKNOWN_ADDRESS, 'success' : false, 'message' : 'A directions request could not be successfully parsed.'};
			break;
		default:
			return {
				'code': null,
				'success': false,
				'message': 'An unknown error occurred.'
			};
		break;
	};
};

Mapifies.AddFeed = function( element, options, callback ) {
	function defaults() {
		return {
			// URL of the feed to pass (required)
			feedUrl: "",
			// Position to center the map on (optional)
			mapCenter: []
		};
	};
	var thisMap = Mapifies.MapObjects.Get(element);
	options = jQuery.extend(defaults(), options);

	// Load feed
	var feed = new google.maps.GeoXml(options.feedUrl);
	// Add as overlay
	thisMap.addOverlay(feed);
	
	// If the user has passed the optional mapCenter,
	// then center the map on that point
	if (options.mapCenter[0] && options.mapCenter[1])
		thisMap.setCenter(new google.maps.LatLng(options.mapCenter[0], options.mapCenter[1]));
		
	if (typeof callback == 'function') return callback( feed, options );
	return;
};

Mapifies.RemoveFeed = function ( element, feed, callback ) {
	var thisMap = Mapifies.MapObjects.Get(element);
	thisMap.removeOverlay(feed);
	if (typeof callback == 'function') return callback( feed, options );
	return;
};

Mapifies.AddGroundOverlay = function( element, options, callback) {
	
	/**
	 * Default options for AddGroundOverlay
	 * @id Mapifies.AddGroundOverlay.defaults
	 * @alias Mapifies.AddGroundOverlay.defaults
	 * @return {Object} The options for AddGroundOverlay
	 * @method
	 * @namespace Mapifies.AddGroundOverlay
	 */
	function defaults() {
		return {
			// South West Boundry
			overlaySouthWestBounds: [],
			// North East Boundry
			overlayNorthEastBounds: [],
			// Image
			overlayImage: ""
		};
	};
	
	var thisMap = Mapifies.MapObjects.Get(element);
	options = jQuery.extend(defaults(), options);
	
	var boundries = new google.maps.LatLngBounds(new google.maps.LatLng(options.overlaySouthWestBounds[0], options.overlaySouthWestBounds[1]), new google.maps.LatLng(options.overlayNorthEastBounds[0], options.overlayNorthEastBounds[1]));
	groundOverlay = new google.maps.GroundOverlay(options.overlayImage, boundries);
	
	thisMap.addOverlay(groundOverlay);
		
	if (typeof callback == 'function') return callback( groundOverlay, options );
	return;
};

Mapifies.RemoveGroundOverlay = function ( element, groundOverlay ) {
	var thisMap = Mapifies.MapObjects.Get(element);
	thisMap.removeOverlay(groundOverlay);
	return;
};

Mapifies.AddMarker = function ( element, options, callback ) {
	
	function defaults() {
		var values = {
			// Point lat & lng
			pointLatLng: [],
			// Point HTML for infoWindow
			pointHTML: null,
			// Event to open infoWindow (click, dblclick, mouseover, etc)
			pointOpenHTMLEvent: "click",
			// Point is draggable?
			pointIsDraggable: false,
			// Point is removable?
			pointIsRemovable: false,
			// Event to remove on (click, dblclick, mouseover, etc)
			pointRemoveEvent: "dblclick",
			// These two are only required if adding to the marker manager
			pointMinZoom: 4,
			pointMaxZoom: 17,
			// Optional Icon to pass in (not yet implemented)
			pointIcon: null,
			// For maximizing infoWindows (not yet implemented)
			pointMaxContent: null,
			pointMaxTitle: null,
			centerMap: false,
			markerType: "default"
		};
		return values;
	};
	
	var thisMap = Mapifies.MapObjects.Get(element);
	options = jQuery.extend({}, defaults(), options);
	var markerOptions = {}
	
	if (typeof options.pointIcon == 'object')
		jQuery.extend(markerOptions, {'icon': options.pointIcon});
		
	if (options.pointIsDraggable)
		jQuery.extend(markerOptions, {'draggable': options.pointIsDraggable});
			
	if (options.centerMap)
		jQuery.jmap.GMap2.setCenter(new google.maps.LatLng(options.pointLatLng[0],options.pointLatLng[1]));
		
	// Create marker, optional parameter to make it draggable
	var marker = new google.maps.Marker(new google.maps.LatLng(options.pointLatLng[0],options.pointLatLng[1]), markerOptions);
		
	// If it has HTML to pass in, add an event listner for a click
	if(options.pointHTML)
		google.maps.Event.addListener(marker, options.pointOpenHTMLEvent, function(){
			marker.openInfoWindowHtml(options.pointHTML);
		});
	// If it is removable, add dblclick event
	if(options.pointIsRemovable)
		google.maps.Event.addListener(marker, options.pointRemoveEvent, function(){
			thisMap.removeOverlay(marker);
		});

	// If the marker manager exists, add it
	if(thisMap.GMarkerManager) {
		thisMap.GMarkerManager.addMarker(marker, options.pointMinZoom, options.pointMaxZoom);
	} else if (thisMap.MarkerManager){
	    thisMap.MarkerManager.addMarker(marker, options.markerType);
	} else {
		// Direct rendering to map
		thisMap.addOverlay(marker);
	}
		
	if (typeof callback == 'function') return callback(marker, options);
	return;
};

Mapifies.RemoveMarker = function (element, marker ) {
	var thisMap = Mapifies.MapObjects.Get(element);
	thisMap.removeOverlay(marker);
	return;
};

Mapifies.CreateGMarkerManager = function(element, options, callback) {
	
	function defaults() {
		return {
			// Border Padding in pixels
			borderPadding: 100,
			// Max zoom level 
			maxZoom: 17,
			// Track markers
			trackMarkers: false
		}
	}
	var thisMap = Mapifies.MapObjects.Get(element);
	options = jQuery.extend(defaults(), options);
	var markerManager = new google.maps.MarkerManager(thisMap, options);
	Mapifies.MapObjects.Append(element, 'GMarkerManager',markerManager);

	// Return the callback
	if (typeof callback == 'function') return callback( options );
};

Mapifies.CreateMarkerManager = function(element, options, callback){
    var markers = {};
    var thisMap = Mapifies.MapObjects.Get(element);
    Mapifies.MapObjects.Append(element, 'MarkerManager',this);
    this.addMarker = function(marker, markerType){
        if (!markers[markerType])
            markers[markerType] = [];
        markers[markerType].push(marker);        
    };
    
    this.removeMarkers = function(callback){
        thisMap.getInfoWindow().hide();
        jQuery.each(markers, function(i){
            jQuery.each(this, function(i){
                thisMap.removeOverlay(this);
            });
        });
        if (typeof callback == 'function') return callback();
    };
    
    this.showMarkers = function(markerType, callback){
        jQuery.each(markers[markerType], function(i){
            thisMap.addOverlay(this);
        });
        if (typeof callback == 'function') return callback();
    };

	// Return the callback
	if (typeof callback == 'function') return callback();
};

Mapifies.AddPolygon = function(element, options, callback) {
	
	function defaults() {
		return {
			// An array of GLatLng objects
			polygonPoints: [],
			// The outer stroke colour
	 		polygonStrokeColor: "#000000",
	 		// Stroke thickness
	 		polygonStrokeWeight: 5,
	 		// Stroke Opacity
	 		polygonStrokeOpacity: 1,
	 		// Fill colour
	 		polygonFillColor: "#ff0000",
	 		// Fill opacity
	 		polygonFillOpacity: 1,
	 		// Optional center map
	 		mapCenter: [],
	 		// Is polygon clickable?
	 		polygonClickable: true
		}
	}
	
	var thisMap = Mapifies.MapObjects.Get(element);
	options = jQuery.extend(defaults(), options);
	var polygonOptions = {};
	
	if (!options.polygonClickable)
		polygonOptions = jQuery.extend(polygonOptions, {clickable: false});
	 		
	if(options.mapCenter[0] && options.mapCenter[1])
		thisMap.setCenter(new google.maps.LatLng(options.mapCenter[0], options.mapCenter[1]));
	
	var allPoints = [];
	jQuery.each(options.polygonPoints, function(i, point) {
		allPoints.push(new google.maps.LatLng(point[0],point[1]));
	});
	
	var polygon = new google.maps.Polygon(allPoints, options.polygonStrokeColor, options.polygonStrokeWeight, options.polygonStrokeOpacity, options.polygonFillColor, options.polygonFillOpacity, polygonOptions);
	thisMap.addOverlay(polygon);
		
	if (typeof callback == 'function') return callback(polygon, polygonOptions, options);
	return;
}

Mapifies.RemovePolygon = function (element, polygon ) {
	var thisMap = Mapifies.MapObjects.Get(element);
	thisMap.removeOverlay(polygon);
	return;
};

Mapifies.AddPolyline = function (element, options, callback) {
	
	/**
	 * Default options for AddPolyline
	 * @id Mapifies.AddPolyline.defaults
	 * @alias Mapifies.AddPolyline.defaults
	 * @return {Object} The options for AddPolyline
	 * @method
	 * @namespace Mapifies.AddPolyline
	 */
	function defaults() {
		return {
			// An array of GLatLng objects
			polylinePoints: [],
			// Colour of the line
			polylineStrokeColor: "#ff0000",
			// Width of the line
			polylineStrokeWidth: 10,
			// Opacity of the line
			polylineStrokeOpacity: 1,
			// Optional center map
			mapCenter: [],
			// Is line Geodesic (i.e. bends to the curve of the earth)?
			polylineGeodesic: false,
			// Is line clickable?
			polylineClickable: true
		};
	};
	
	var thisMap = Mapifies.MapObjects.Get(element);
	options = jQuery.extend(defaults(), options);
	var polyLineOptions = {};
	if (options.polylineGeodesic)
		jQuery.extend(polyLineOptions, {geodesic: true});
			
	if(!options.polylineClickable)
		jQuery.extend(polyLineOptions, {clickable: false});

	if (options.mapCenter[0] && options.mapCenter[1])
		thisMap.setCenter(new google.maps.LatLng(options.mapCenter[0], options.mapCenter[1]));

	var allPoints = [];
	jQuery.each(options.polylinePoints, function(i, point) {
		allPoints.push(new google.maps.LatLng(point[0],point[1]));
	});

	var polyline = new google.maps.Polyline(allPoints, options.polylineStrokeColor, options.polylineStrokeWidth, options.polylineStrokeOpacity, polyLineOptions);
	thisMap.addOverlay(polyline);
		
	if (typeof callback == 'function') return callback(polyline, polyLineOptions, options);
	return;
};

Mapifies.RemovePolyline = function (element, polyline, callback ) {
	var thisMap = Mapifies.MapObjects.Get(element);
	thisMap.removeOverlay(polyline);
	return;
};

Mapifies.AddScreenOverlay = function( element, options, callback ) {
	
	/**
	 * Default options for AddScreenOverlay
	 * @id Mapifies.AddScreenOverlay.defaults
	 * @alias Mapifies.AddScreenOverlay.defaults
	 * @return {Object} The options for AddScreenOverlay
	 * @method
	 * @namespace Mapifies.AddScreenOverlay
	 */
	function defaults() {
		return {
			'imageUrl':'',
			'screenXY':[],
			'overlayXY':[],
			'size':[]
		};
	};
	var thisMap = Mapifies.MapObjects.Get(element);
	options = jQuery.extend(defaults(), options);

	var overlay = new google.maps.ScreenOverlay(options.imageUrl, new google.maps.ScreenPoint(options.screenXY[0],options.screenXY[1]), new google.maps.ScreenPoint(options.overlayXY[0],options.overlayXY[1]), new google.maps.ScreenSize(options.size[0],options.size[1]));
	thisMap.addOverlay(overlay);
		
	if (typeof callback == 'function') return callback(overlay, options);
};

Mapifies.RemoveScreenOverlay = function ( element, overlay ) {
	var thisMap = Mapifies.MapObjects.Get(element);
	thisMap.removeOverlay(overlay);
	return;
};

Mapifies.CreateStreetviewPanorama = function( element, options, callback ) {
	
	function defaults() {
		return {
			'overideContainer':'',
			'latlng':[40.75271883902363, -73.98262023925781],
			'pov': []
		}
	};
	var thisMap = Mapifies.MapObjects.Get(element);
	options = jQuery.extend(defaults(), options);
	// Create Street View Overlay
	
	var container = null;
	if (options.overideContainer !== '') {
		container = jQuery(options.overideContainer).get(0);
	} else {
		container = jQuery(element).get(0);
	}
	
	var viewOptions = {};
	if (options.pov.length > 0) {
		jQuery.extend(viewOptions, {'pov':new google.maps.Pov(options.latlng[0],options.latlng[1],options.latlng[2])});
	}
	if (options.latlng.length > 0) {
		jQuery.extend(viewOptions, {'latlng':new google.maps.LatLng(options.latlng[0],options.latlng[1])});
	}
	
	var overlay = new google.maps.StreetviewPanorama(container, viewOptions);
	if (typeof callback == 'function') return callback(overlay, options);
	return;
};

Mapifies.RemoveStreetviewPanorama = function ( element, view, callback ) {
	var thisMap = Mapifies.MapObjects.Get(element);
	view.remove();
	if (typeof callback == 'function') return callback( view );
	return;
};

Mapifies.AddTrafficInfo = function( element, options, callback) {
	
	/**
	 * Default options for AddTrafficInfo
	 * @id Mapifies.AddTrafficInfo.defaults
	 * @alias Mapifies.AddTrafficInfo.defaults
	 * @return {Object} The options for AddTrafficInfo
	 * @method
	 * @namespace Mapifies.AddTrafficInfo
	 */
	function defaults() {
		return {
			// Center the map on this point (optional)
			mapCenter: []
		};
	};
	var thisMap = Mapifies.MapObjects.Get(element);
	options = jQuery.extend(defaults(), options);

	var trafficOverlay = new google.maps.TrafficOverlay;
	// Add overlay
	thisMap.addOverlay(trafficOverlay);
	// If the user has passed the optional mapCenter,
	// then center the map on that point
	if (options.mapCenter[0] && options.mapCenter[1]) {
		thisMap.setCenter(new google.maps.LatLng(options.mapCenter[0], options.mapCenter[1]));
	}
	if (typeof callback == 'function') return callback(trafficOverlay, options);
};

Mapifies.RemoveTrafficInfo = function ( element, trafficOverlay ) {
	var thisMap = Mapifies.MapObjects.Get(element);
	thisMap.removeOverlay(trafficOverlay);
	return;
};

Mapifies.SearchAddress = function( element, options, callback) {
	
	/**
	 * Default options for SearchAddress
	 * @method
	 * @namespace Mapifies.SearchAddress
	 * @id Mapifies.SearchAddress.defaults
	 * @alias Mapifies.SearchAddress.defaults
	 * @return {Object} The options for SearchAddress
	 */
	function defaults() {
		return {
			// what to return, "latlng" or "points"
			type: 'latlng',
			// Address to search for
			address: null,
			// Optional Cache to store Geocode Data (not implemented yet)
			cache: {},
			// Country code for localisation (not implemented yet)
			countryCode: 'uk'
		};
	};
	var thisMap = Mapifies.MapObjects.Get(element);
	options = jQuery.extend(defaults(), options);
			
	// Check to see if the Geocoder already exists in the object
	// or create a temporary locally scoped one.
	if (typeof thisMap.Geocoder == 'undefined') {
		var geocoder = new google.maps.ClientGeocoder;
	} else {
		var geocoder = thisMap.Geocoder;
	}
		
	// Geocode the address
	switch (options.type) {
		case 'latlng':
			geocoder.getLatLng(options.address, function(point){
				if (typeof callback == 'function') return callback(point, options);
			});
		break;
		case 'points':
			geocoder.getLocations(options.address, function(points){
				if (typeof callback == 'function') return callback(points, options);
			});
		break;
	};
	
	return;
};

Mapifies.SearchDirections = function( element, options, callback) {
	function defaults() {
		return {
			// From address
			'directions': '',
			// Optional panel to show text directions
			'panel': "",
			//The locale to use for the directions result.
			'locale': 'en_US',
			//The mode of travel, such as driving (default) or walking
			'travelMode': 'driving',
			// Option to avoid highways
			'avoidHighways': false,
			// Get polyline
			'getPolyline': true,
			// Get directions
			'getSteps': true,
			// Preserve Viewport
			'preserveViewport' : false
		};
	};
	var thisMap = Mapifies.MapObjects.Get(element);
	options = jQuery.extend(defaults(), options);
	
	var queryOptions = {
		'locale': options.locale,
		'travelMode': options.travelMode,
		'avoidHighways': options.avoidHighways,
		'getPolyline': options.getPolyline,
		'getSteps': options.getSteps,
		'preserveViewport' : options.preserveViewport
	};
	
	var panel = $(options.panel).get(0);
	if (!thisMap.Directions)
	{
	    var directions = new google.maps.Directions(thisMap, panel);
	    Mapifies.MapObjects.Append(element, 'Directions', directions);
	}
	
	
	GEvent.addListener(thisMap.Directions, "load", onLoad);
    GEvent.addListener(thisMap.Directions, "error", onError);
	
	thisMap.Directions.load(options.directions, queryOptions);
	
	function onLoad() {
		if (typeof callback == 'function') return callback(thisMap.Directions, options);	
	}
	
	function onError() {
		if (typeof callback == 'function') return callback(thisMap.Directions, options);	
	}
	
	return;
};

function SearchDirectionsCode(code){
	switch (code) {
		case G_GEO_SUCCESS:
			return {'code':G_GEO_SUCCESS,'success':true,'message':'Success'};
		case G_GEO_UNKNOWN_ADDRESS:
			return {'code' : G_GEO_UNKNOWN_ADDRESS, 'success' : false, 'message' : 'No corresponding geographic location could be found for one of the specified addresses. This may be due to the fact that the address is relatively new, or it may be incorrect'};
			break;
		case G_GEO_SERVER_ERROR:
			return {'code' : G_GEO_UNKNOWN_ADDRESS, 'success' : false, 'message' : 'A geocoding or directions request could not be successfully processed, yet the exact reason for the failure is not known.'};
			break;
		case G_GEO_MISSING_QUERY:
			return {'code' : G_GEO_UNKNOWN_ADDRESS, 'success' : false, 'message' : 'The HTTP q parameter was either missing or had no value. For geocoder requests, this means that an empty address was specified as input. For directions requests, this means that no query was specified in the input.'};
			break;
		case G_GEO_BAD_KEY:
			return {'code' : G_GEO_UNKNOWN_ADDRESS, 'success' : false, 'message' : 'The given key is either invalid or does not match the domain for which it was given.'};
			break;
		case G_GEO_BAD_REQUEST:
			return {'code' : G_GEO_UNKNOWN_ADDRESS, 'success' : false, 'message' : 'A directions request could not be successfully parsed.'};
			break;
		default:
			return {
				'code': null,
				'success': false,
				'message': 'An unknown error occurred.'
			};
		break;
	};
};

Mapifies.CreateAdsManager = function( element, options, callback) {

	/**
	 * Default options for CreateAdsManager
	 * @method
	 * @namespace Mapifies.CreateAdsManager
	 * @id Mapifies.CreateAdsManager.defaults
	 * @alias Mapifies.CreateAdsManager.defaults
	 * @return {Object} The options for CreateAdsManager
	 */

	function defaults() {
		return {
			'publisherId':'',
			'maxAdsOnMap':3,
			'channel':0,
			'minZoomLevel':6
		}
	};
	var thisMap = Mapifies.MapObjects.Get(element);
	options = jQuery.extend(defaults(), options);
	
	var adsOptions = {
		'maxAdsOnMap':options.maxAdsOnMap,
		'channel':options.channel,
		'minZoomLevel':options.minZoomLevel
	}
	
	var adsManager = new google.maps.AdsManager(thisMap, options.publisherId, adsOptions);
	if (typeof callback == 'function') return callback(adsManager, options);
};

Mapifies.LoadMarkers = function (filePath, element, options, callback){
    var thisMap = Mapifies.MapObjects.Get(element);
    //options = jQuery.extend(defaults(), options);

    $.ajax({type:"GET",url:filePath,dataType:"xml",
        success:function(data,textStatus) {
            $(data).find('locations').each(function() {
		        var type = $(this).attr("type");
		        var image = $(this).attr("image");
                var size = [parseInt($(this).attr("size").split(",")[0]), parseInt($(this).attr("size").split(",")[1])];
                var anchor = [parseInt($(this).attr("anchor").split(",")[0]), parseInt($(this).attr("anchor").split(",")[1])];
                var infoWinAnchor = [parseInt($(this).attr("infoWinAnchor").split(",")[0]), parseInt($(this).attr("infoWinAnchor").split(",")[1])];
    		    
                $(this).find("marker").each(function(){
			        var lat = parseFloat($(this).attr("lat"));
                    var lng = parseFloat($(this).attr("lng"));
                    var html = $("html",this).text();
                    
    		        var icon = createIcon({'iconImage':image, 'iconSize':size, 'iconAnchor':anchor, 'iconInfoWindowAnchor':infoWinAnchor});                
                    Mapifies.AddMarker(element, {'pointLatLng':[lat,lng], 'pointHTML':html, 'pointIcon':icon, 'markerType':type});
                });
            });
            
	        if (typeof callback == 'function') return callback(element, options);
        }
    });
};

//  Global function for the toAddress combo box item changed
function HandleToAddressChanging(sender, args)
{    
    var item = args.get_item();
    var thisMap = Mapifies.MapObjects.Get(jQuery(item.get_attributes().getAttribute("map")));
    if ((item.get_value() == "n/a") || (item.get_value() == ""))
    {
	    sender.set_text("Choose a Location ....");
	    thisMap.ToAddress = '';
	    return false;
    }
    else
    {
	    thisMap.ToAddress = item.get_value();
    }
}

//  Global function for the fromAddress combo box closing event
function HandleFromAddressClosing(sender, args)
{
    var item = sender.get_items().getItem(0);
    var thisMap = Mapifies.MapObjects.Get(jQuery(item.get_attributes().getAttribute("map")));
    var fromAddress = "";

    jQuery(":input").each(function(i){
        if ($(this).attr("id").indexOf(sender.get_id() + "_i0_address") == 0)
        {
            if ($(this).val() != "")
                fromAddress += $(this).val() + " ";
        }
        
        if ($(this).attr("id").indexOf(sender.get_id() + "_i0_city") == 0)
        {
            if ($(this).val() != "")
                fromAddress += $(this).val() + ", ";
        }
        
        if ($(this).attr("id").indexOf(sender.get_id() + "_i0_state") == 0)
        {
            if ($(this).val() != "")
                fromAddress += $(this).val() + " ";
        }
        
        if ($(this).attr("id").indexOf(sender.get_id() + "_i0_zip") == 0)
        {
            if ($(this).val() != "")
                fromAddress += $(this).val();
        }
    });
    thisMap.FromAddress = fromAddress;
    if (fromAddress == "")
    {
        fromAddress = sender.get_emptyMessage();
    }
    
    sender.set_text(fromAddress);
    sender.set_value(fromAddress);
}

//  Global function that flags the combo box's close property
function toggleBox(allow)
{
    toggleDropDown = allow;
}

//  Global function to toggle the markers by marker type
function toggleMarkers(map, markerType)
{
    var thisMap = Mapifies.MapObjects.Get(jQuery(map));
    if (thisMap.MarkerManager)
    {
        thisMap.MarkerManager.removeMarkers(function(){
            thisMap.MarkerManager.showMarkers(markerType);
        });
        
    }
}

(function($){
	$.fn.jmap = function(method, options, callback) {
		return this.each(function(){
			if (method == 'init' && typeof options == 'undefined') {
				new Mapifies.Init(this, {}, null);
			} else if (method == 'init' && typeof options == 'object') {
				new Mapifies.Init(this, options, callback);
			} else if (method == 'init' && typeof options == 'function') {
				new Mapifies.Init(this, {}, options);
			} else if (typeof method == 'object' || method == null) {
				new Mapifies.Init(this, method, options);
			} else {
				try {
					new Mapifies[method](this, options, callback);
				} catch(err) {
					throw Error('Mapifies Function Does Not Exist');
				}
			}
		});
	}
})(jQuery);
