/*
 * Universal Google Maps Object - version 3.0.10
 *
 */

	
var UGMO = function(divname){
	return new UGMO.fn.init(divname);
};


UGMO.fn = UGMO.prototype = {
	/** @lends UGMO# */
		
	/**
    Intitialize UGMO
    @class Universal Google Maps Object
    @constructs
    @param {String|dom-object|JQuery-object} divname Dom-element to put the map in
    */
	init: function(divname){
		
		/**
		Default settings for the map. Needs to be changed before calling UGMO.show
		@namespace 
		*/
		this.settings = {
		
		    /** 
		    Lattitude part of the initial center of the map
		    @type Float
		    @default 0
		    @public 
		    */
			centerLat:				0,
			
			/** 
		    Longitude part of the initial center of the map
		    @type Float
		    @default 20
		    */
			centerLon:				20,
			
			/** 
		    Initial zoomlevel
		    @type Integer
		    @default 1
		    */
			zoomLevel:				1,
			
			/** 
		    Minimum zoomlevel for the map
		    @type Float
		    @default 1
		    */
			minZoom:				1,
			
			/** 
		    Maximum zoomlevel for the map
		    @type Float
		    @default 20
		    */
			maxZoom:				20,
			
			/** 
		    Set the initial overlay for the map. Has to be an element of UGMO.mapTypes 
		    @link UGMO.mapTypes
		    @type mapTypes
		    @default 'normal'
		    */
	        mapType:				'normal',
	        
	        /** 
		    Controls if the map type controls should be shown
		    @type Boolean
		    @default true
		    */
	        mapTypeControl:			true,
	        
	        /** 
		    The position of the map type controls
		    @type google.maps.ControlPosition
		    @default google.maps.ControlPosition.TOP_RIGHT
		    */
	        mapTypeControlPosition: google.maps.ControlPosition.TOP_RIGHT,
			
	        /** 
		    Controls if the map navigation controls should be shown
		    @type Boolean
		    @default true
		    */
			navigationControl:		true,
			
			/** 
		    The position of the map navigation controls
		    @type google.maps.ControlPosition
		    @default google.maps.ControlPosition.TOP_RIGHT
		    */
			navigationControlPosition: google.maps.ControlPosition.TOP_LEFT,
			
			/** 
		    The stype of the map navigation controls
		    @type google.maps.NavigationControlStyle
		    @default google.maps.NavigationControlStyle.DEFAULT
		    */
			NavigationControlStyle:	google.maps.NavigationControlStyle.DEFAULT,
			
			/** 
		    Controls if Street View is available
		    @type Boolean
		    @default true
		    */
			streetViewControl:		true,
			
			/** 
		    Get only markers within the bounds of the map, advised when using many markers
		    @type Boolean
		    @default false
		    */
			getOnlyMarkersWithinBounds: false,
			
			/** 
		    This is where to fetch the data for the markers
		    @type String
		    @default ''
		    */
			getMarkersURL:			'',					// url to get multiple markers
			
			/** 
		    This is where to fetch the location data for a single marker. This is not the url to be used for the marker info to show in a infoWindow!
		    @type String
		    @default ''
		    */
			getMarkerURL:			'',					// url to get a singe marker
			
			/** 
		    Event for a marker on which to show the infoWindow
		    @type String
		    @default 'click'
		    */
			getMarkerInfoEvent:		'click',
			
			/** 
		    This is where the data to show the infoWindow is fetched
		    @type String
		    @default ''
		    */
			getMarkerInfoURL:		'',                 // url to get info for specific marker
			
			/** 
		    Adjust the center and zoomlevel of the map after fetching markers
		    @type Boolean
		    @default false
		    */
			zoomToExtend:           false,              //extend the map to the retrieved markers after first update
			
			/** 
		    Zoomlevel to use if UGMO.settings.zoomToExtend = true, but there is only 1 marker
		    @type Integer
		    @default 14
		    */
			singleMarkerZoomLevel:  14,                 //zoomlevel to use when there is only one marker on the map and we have to zoom to extend
			
			/** 
		    If a request for markers is already in progress kill it before doing a new request. This is ignored when UGMO.getMarkers gets a custom callback.
		    @type Boolean
		    @default false
		    */
			oneGetMarkersRequestAtATime:      false,     //Only do one getMarkers request to server at a time. Kill a previous one.
			dragTimeout:            2000,                //timeout before listening another dragevent
			
			
			/**
			Default timeout for a getMarkers request
			@type Integer
			@default 6000
			*/
			getMarkersTimeout:		6000
		};
		
		/*
		Holder variables for things that need to be available throughout UGMO and plugins	
		*/
		
		/** 
        Holder for the div in which the map is placed
        */
		this.mapdiv = null;
		
		/** 
        Holder for the Google Maps interface object
        */
		this.map = null;
		
		/** 
        StreetView holder
        */
		this.sv = null;
		
		//StreetViewService Holder
		this.svService = null;
		
		/** 
        Holder for the active infowindow
        */
		this.activeInfowindow = null;
		
		/** 
        Holders for eventhandlers
        */
		this.eventHandlers = {
			moveEndListener: null,
			moveEndHandler: null,
			clickEventListener: null,
			clickEventHandler: null,
			zoomEndListener: null,
			zoomEndHandler: null
		};
		
		/** 
        Holders for al the markers. Referenced by id.
        */
		this.markers = {};
		
		/** 
        Holders for al the icons. Referenced by id.
        */
		this.icons = {};
		
		/** 
        Holders for al the getMarkersRequest
        */
		this.getMarkersRequest = null;
		
		// set div name
		this.settings.divname = divname;
		
		//decides if a dragevent is listened to
		this.dragStop = false;
		
		//holder for the custom marker events
		this.customMarkerEvents = [];
		
		//end of the init function
		return this;
	},
	
    /** 
    @namespace Types of available overlays
    */
    mapTypes: 				{ 'satellite':    google.maps.MapTypeId.SATELLITE,
                            'hybrid':       google.maps.MapTypeId.HYBRID,
                            'normal':       google.maps.MapTypeId.ROADMAP,
                            'terrain':      google.maps.MapTypeId.TERRAIN
                            },
    /**
    Show and initialize the map. All settings need to be done before calling this method.
    @see UGMO#settings
    */
    show: function(){
        // get div for map
		if(typeof(this.settings.divname) === 'object'){
		    this.mapdiv = (this.settings.divname.nodeType) ? this.settings.divname : (
		        (this.settings.divname.jquery) ? this.settings.divname[0] : null);

			this.settings.divname   = this.settings.divname.id;
		}else if(typeof(this.settings.divname) === 'string'){
        	this.mapdiv 			= document.getElementById(this.settings.divname);
		}
        
        if(!this.mapdiv || !this.mapdiv.nodeType){
            throw("Incorrect id for settings.divname: '" + this.settings.divname + "'");
        }
        
        //check settings
        if(isNaN(this.settings.centerLat)){
            throw("settings.centerLat needs to be a number!");
        }
        if(isNaN(this.settings.centerLon)){
            throw("settings.centerLat needs to be a number!");
        }
        if(isNaN(this.settings.zoomLevel)){
            throw("settings.zoomLevel needs to be a number!");
        }
        if(this.settings.zoomLevel % 1 !== 0){
            throw("settings.zoomLevel needs to be an integer!");
        }
        
        if(!this.settings.mapType in this.mapTypes){
            throw("undefined mapType given: '" + this.settings.mapType + "'");
        }
        
        if(typeof google.maps !== "undefined"){
        
            //map options
            var mapOptions = {  
                                'mapTypeId':                  this.mapTypes[this.settings.mapType],
                                'mapTypeControl':             this.settings.mapTypeControl,
                                'mapTypeControlOptions':      { 'position': this.settings.navigationControlPosition,
                                                                'style': this.settings.NavigationControlStyle},
                                'navigationControl':          this.settings.navigationControl,
                                'navigationControlOptions':   { 'style': this.settings.NavigationControlStyle,
                                                                'position': this.settings.navigationControlPosition},
                                'center':                     new google.maps.LatLng(this.settings.centerLat, this.settings.centerLon),
                                'zoom':                       parseInt(this.settings.zoomLevel),
								'minZoom':					  parseInt(this.settings.minZoom),
								'maxZoom':					  parseInt(this.settings.maxZoom),
                                'streetViewControl':          this.settings.streetViewControl
                            };
            
            if(typeof this.settings.streetViewControlOptions == 'object'){
                mapOptions.streetViewControlOptions = this.settings.streetViewControlOptions;
            }
            
            // create Google Maps object
            this.map = new google.maps.Map(this.mapdiv, mapOptions);
            
            //define ugmo_ for use in het eventHandler functions
            var ugmo_ = this;
            
            //create eventhandling functions
            this.eventHandlers.dragEndHandler = function(element){
                if(ugmo_.settings.getOnlyMarkersWithinBounds && !ugmo_.dragStop){
                    ugmo_.update();
                }
                
                if(!ugmo_.dragStop){
                    setTimeout(function(){
                        ugmo_.dragStop = true;
                    }, 0);
                    
                    setTimeout(function(){
                        ugmo_.dragStop = false;
                    }, ugmo_.settings.dragTimeout);
                }
            };
            this.eventHandlers.clickEventHandler = function(element){
                if(element === null && ugmo_.activeInfowindow){
                    //close any open infowindows
                    ugmo_.activeInfowindow.hide();
                }
            };
            this.eventHandlers.zoomEndHandler = function(element){
				
                if(ugmo_.settings.getOnlyMarkersWithinBounds){
                    // wait until the map is done loading
                    google.maps.event.addListenerOnce(ugmo_.map, 'idle', function(){
                        ugmo_.update();
                    });
                }
            };
            
            // attach standard event handlers (moving map, changing zoomlevel)
            this.eventHandlers.dragEndListener = google.maps.event.addListener(this.map, "dragend", this.eventHandlers.dragEndHandler);
            this.eventHandlers.clickEventListener = google.maps.event.addDomListener(this.map, "click", this.eventHandlers.clickEventHandler);
            this.eventHandlers.zoomEndListener = google.maps.event.addListener(this.map, "zoom_changed", this.eventHandlers.zoomEndHandler);
            
            // wait until the map is done loading
            google.maps.event.addListenerOnce(ugmo_.map, 'idle', function(){
                ugmo_.update(ugmo_.settings.zoomToExtend);
            });
            
        }else{
            mapdiv.innerHTML = "Your browser is not compatible with Google Maps!";
        }
    },
    
    
    /**
    Update the map.
    This function only calls getMarkers and is called by UGMO.show. For plugins extends getMarkers, not update.
    @param {Boolean} zoomToExtend Zoom and center the map to show all the markers.
    @param {boolean} hideCurrentMarkers Replace the current markers on the map.
    */
    update: function(zoomToExtend, hideCurrentMarkers){
        // get markers to show on map (if a location to fetch them was specified)
		if(this.settings.getMarkersURL){
            this.getMarkers({}, zoomToExtend, hideCurrentMarkers);
        }
    },
    
    /**
    Get the markers from the server
    @param {Object} requestData Object-literal with request data to send to the server with the markers request. Use this to change which markers are returned.
    @param {Boolean} zoomToExtend Zoom and center the map to show all the markers.
    @param {Boolean} hideCurrentMarkers Replace the current markers on the map.
    @param {Function} Function to execute when the request to the server is done. By default this is UGMO.drawMarkers. For plugins extends drawMarkers, don't use the callback function.
    */
    getMarkers: function(requestData, zoomToExtend, hideCurrentMarkers, callbackFunction, failCallbackFunction, timeout){
        //set the variable to store the requestdata in
        var requestData = (typeof requestData !== "undefined") ? requestData : {};
        
        //if zoomToExtend and hideCurrentMarkers are not set, presume false
        var zoomToExtend = (typeof zoomToExtend !== "undefined") ? zoomToExtend : false;
        var hideCurrentMarkers = (typeof hideCurrentMarkers !== "undefined") ? hideCurrentMarkers : false;
		
        //if only the markers within the bounds should be fetched
        if(this.settings.getOnlyMarkersWithinBounds){
            // get boundaries of map
            var bounds								= this.map.getBounds();
            var sw 									= bounds.getSouthWest();
            var ne 									= bounds.getNorthEast();
            var boundsString 						= sw.lng() + "," + sw.lat() + "," + ne.lng() + "," + ne.lat();
            
            requestData.bounds 						= boundsString;
        }
        
        //define ugmo_ for use in the ajax request
        var ugmo_ = this;
        
        //If there is another request going and we need kill it and this is not a special request
        if(this.settings.oneGetMarkersRequestAtATime && this.getMarkersRequest && !callbackFunction){
            this.getMarkersRequest.abort();
        }
		
		var timeout = (typeof(timeout) === 'undefined') ? ugmo_.settings.getMarkersTimeout : timeout;
        
        //do the request
        this.getMarkersRequest = $.ajax({
            url: ugmo_.settings.getMarkersURL,
            data: requestData,
            dataType: 'json',
            success: function(data) {
				if(hideCurrentMarkers){
                    // clear existing markers
                    ugmo_.removeMarkers();
                }
                
				if(callbackFunction){
                    callbackFunction.apply(ugmo_, [data, zoomToExtend]);
                }else{
                    ugmo_.drawMarkers(data, zoomToExtend);
                }
                
                this.getMarkersRequest = null;
            },
			timeout: timeout,
            error: function(xhr, ajaxOptions, thrownError) {
				if(thrownError != 'abort'){
                    if(failCallbackFunction){
                        failCallbackFunction();
                    }else{
                        ugmo_.requestFailed();
                    }
                }
            }
        });
        
        //if there is a custom callback function we want this request left alone
        if(callbackFunction){
            this.getMarkersRequest = null;
        }
    
    },
    
    /**
    Get one marker with its source and id given. Only gets the location data, no extra info.
    @param {String} source Source of the marker, only use if multiple sources are defined, otherwise set to null.
    @param {Boolean} id The external id of the marker. Not UGMO's internal id.
    @param {Boolean} zoomToExtend Zoom and center the map to show all the markers.
    @param {Function} Function to execute when the request to the server is done. By default this is UGMO.drawMarkers. For plugins extends drawMarkers, don't use the callback function.
    */
    getMarker: function(source, id, zoomToExtend, callbackFunction){
    
        //set the variable to store the requestdata in
        var requestData = {
            source: source,
            id: id
        };
        
        //if zoomToExtend is not set, presume false
        var zoomToExtend = (typeof zoomToExtend !== "undefined") ? zoomToExtend : false;
        
        //define ugmo_ for use in the ajax request
        var ugmo_ = this;
        //do the request
        $.ajax({
            url: this.settings.getMarkersURL,
            data: requestData,
            dataType: 'json',
            success: function(data) {
                if(callbackFunction){
                    callbackFunction.apply(ugmo_, [data, zoomToExtend]);
                }else{
                    ugmo_.drawMarkers(data, zoomToExtend);
                }
            },
            error: function(xhr, ajaxOptions, thrownError) {
                ugmo_.requestFailed();
            }
        });
    },
    
    /**
    Draw the fetched marker(s) retrieved from the server.
    @param {Object} jsondata Object-literal with data from the server.
    @param {Boolean} zoomToExtend Zoom and center the map to show all the markers.
    */
    drawMarkers: function(jsondata, zoomToExtend){
        if(jsondata) {				
            // loop through icons
            if(jsondata.icons !== undefined){
                var icon = null;	
				
                for(var iconnum in jsondata.icons){
					id 		= jsondata.icons[iconnum].id;
					if(!this.isKnownIcon(id)){
                    	icon = UGMOIcon(this, jsondata.icons[iconnum]);
                    	this.icons[icon.data.id] = icon;
					}
                }
            }
            
            if(zoomToExtend && !this.bounds){
                this.bounds = new google.maps.LatLngBounds();
            }
                
            // loop through markers
            var marker		= null;
            var id, source, int_id;
			
			var numberOfLocationMarkers = 0;
			
            if(jsondata.markers !== undefined){
				
                for(var markernum in jsondata.markers){
                    if(jsondata.markers[markernum].lat !== null && jsondata.markers[markernum].lat !== '' && jsondata.markers[markernum].lon !== null && jsondata.markers[markernum].lon !== ''){
                        
                        numberOfLocationMarkers++;
                        
                        id 							= jsondata.markers[markernum].id;
                        source						= (jsondata.markers[markernum].source !== undefined) ? jsondata.markers[markernum].source : '';
                        // make internal id for marker to use in associative array
                        int_id						= source + id;
                        
                        if(typeof(this.markers[int_id]) === 'undefined'){
                            marker = UGMOMarker(this, jsondata.markers[markernum]);
                        }else{
                            marker = this.markers[int_id];
                        }
                        
                        if(zoomToExtend){
                            this.bounds.extend(new google.maps.LatLng(marker.data.lat, marker.data.lon));
                        }
                    }
                }
				
            }else{
                throw("No markers object return in json!");
            }
            
            if(zoomToExtend){
                //only fit bounds if more than one marker
                if(numberOfLocationMarkers === 0){
                    // nothing
                }else if(numberOfLocationMarkers > 1){
                    this.map.fitBounds(this.bounds);
                }else if(jsondata.markers.length > 0){
                    //fall back to singleMarkerZoomLevel
                    this.map.setCenter(this.bounds.getCenter());
                    this.map.setZoom(this.settings.singleMarkerZoomLevel);
                }
            }
        }else{
            this.requestFailed();
        }
    },
	
    /**
    Remove all te markers from the map
    */
	removeMarkers: function(){
		
		for(var int_id in this.markers){
			this.markers[int_id].marker.setMap(null); 
			delete(this.markers[int_id]);
		}
		
		// delete all icons too
		for(var int_id in this.icons){
			delete(this.icons[int_id]);
		}
		
		//reset the bounds
		this.bounds = null;
	},
	
    /**
    Check if the there is an icon for a given icon id
    @param {String} id Id of the icon in question.
    */
	isKnownIcon: function(id){  
		if(this.icons[id] !== undefined){
			return this.icons[id];
		} else {
			return false;
		}
	},
    
    
    /**
    This function is called when a request to the server fails.
    */
    requestFailed: function(){
	//throw won't work here
        console.warn("The connection with the server could not be established. (" + this.settings.getMarkersURL + ")");
    },
    
    /**
    Show the map (instead of Street View)
    */
    showMap: function(){
	    if(this.sv){
            this.sv.setVisible(false);
        }
	},
	
    /**
    Set the minimum allowed zoomlevel.
    @param {Integer} newLevel Minumum allowed zoomlevel
    */
	setMinZoom: function(newLevel){
		this.map.minZoom = newLevel;
	},
	
    /**
    Set the maximum allowed zoomlevel.
    @param {Integer} newLevel Maximum allowed zoomlevel
    */
	setMaxZoom: function(newLevel){
		this.map.maxZoom = newLevel;
	},
	
	/**
    Set the maximum allowed zoomlevel.
    @param {Integer} newLevel Maximum allowed zoomlevel
    */
	getMaxZoom: function(){
		return(this.map.maxZoom);
	},
	
	/**
    Attach a custom event to a marker
    @param {String} event type of event
    @param {Function} callback function to execute
    */
    addCustomMarkerEvent: function(event, callback){
        this.customMarkerEvents.push({'event':event, 'callback':callback});
    },
    
    /**
    Set the terrain type.
    @param {String} mapType
    */
    setMapType: function(mapType){
        if(!mapType in this.mapTypes){
            throw("undefined mapType given: '" + mapType + "'");
        }
        
        this.map.setMapTypeId(this.mapTypes[mapType]);
    }
};

/*
UGMOMarker

Object to handle the markers from UGMO
*/
var UGMOMarker = function(ugmo_, markerData){
    return new UGMOMarker.fn.init(ugmo_, markerData);
};

UGMOMarker.fn = UGMOMarker.prototype = {
    /** @lends UGMOMarker# */
	  
    //store the Google LatLng
    markerLatLon: null,
	
	/**
    Intitialize UGMOMarker
    @class
    @constructs
    @param {UGMO} ugmo_ Reference to the ugmo-instance this marker belongs to.
    @param {Object} markerData Object with marker info from the server.
    */  
    init: function(ugmo_, markerData){
		
        //id for this marker
        var id = markerData.id;
        this.ugmo_ = ugmo_;
        
        // source of full information for this marker
        var source					= (markerData.source !== undefined) ? markerData.source : '';
        
        // make internal id for marker to use in associative array
        this.int_id					= source + id;
	
        //store data for this marker
        this.data = markerData;
        
	    //eventHandlers
	    this.getMarkerInfoEventListener = null;
        
        if(typeof(this.ugmo_.markers[this.int_id]) === 'undefined'){
            this.ugmo_.markers[this.int_id] 		= this;
        
            //select icon
            var icon = null;
            var shadow = null;
			
            if(ugmo_.icons[this.data.icon] !== undefined && ugmo_.icons[this.data.icon].icon !== undefined){
                icon = ugmo_.icons[this.data.icon].icon;
                shadow = ugmo_.icons[this.data.icon].shadow;
            }
            // create marker
            this.markerLatLon 			= new google.maps.LatLng(this.data.lat, this.data.lon);
            
            var markerOptions 			= { position:   this.markerLatLon,
            								icon :      icon,
										    shadow:     shadow,
                                            clickable:  true,
                                            map:        this.ugmo_.map
                                        };
                                        //
            this.marker 			  	= new google.maps.Marker(markerOptions);
        
            //define marker_ for use in the eventHandlers
            var marker_ = this;
            
            // if we have to show markerInfo on mouseover or on click
            if(this.ugmo_.settings.getMarkerInfoEvent){
                
                // add event handler to do so
                this.getMarkerInfoEventListener = google.maps.event.addDomListener(this.marker, this.ugmo_.settings.getMarkerInfoEvent, function () {
                    marker_.selectMarker();
                });
                
                // and add handler to remove window on mouseout (only if event used to show marker is mouseover)
                if(this.ugmo_.settings.getMarkerInfoEvent === "mouseover"){
                    this.ugmo_.hideWindowOnMouseOut = google.maps.event.addDomListener(this.marker, "mouseout", function() {
						if(typeof(marker_.ugmo_.currentInfowindow) !== 'undefined'){
                        	setTimeout(marker_.ugmo_.currentInfowindow.hide, marker_.ugmo_.settings.infoWindowTimeOut);
						}
                    });	
                }
                                
            }
                        
            //and add all custom events
            if(this.ugmo_.customMarkerEvents.length){
                for(var index in this.ugmo_.customMarkerEvents){
                    if(this.ugmo_.customMarkerEvents.hasOwnProperty(index)){
                        google.maps.event.addDomListener(this.marker, this.ugmo_.customMarkerEvents[index].event, function () {
                            marker_.ugmo_.customMarkerEvents[index].callback.apply(marker_);
                        });
                    }
                }
            }
        }
    },
	
	/**
    This method is called when a marker is selected with the UGMO.settings.getMarkerInfoEvent (normally click)
    @param {Function} callbackFunction If set, this function is called after the the request instead of showMarkerInfo.
    */ 
	selectMarker: function(callbackFunction){
		var url = "";
		
		switch(typeof(this.ugmo_.settings.getMarkerInfoURL)){
			case 'boolean':
				// url was not specified
				alert('URL to use to fetch markerinfo was not specified!');
				break;
			case 'object':
				// check if source (where to find markerInfo) of this marker was specified
				if(typeof(this.data.source) == 'string' && this.data.source.length > 0){
					if(this.ugmo_.settings.getMarkerInfoURL.hasOwnProperty(this.data.source)){
						url = this.ugmo_.settings.getMarkerInfoURL[this.data.source];
					}else{
						throw('The source for marker with id ' + this.data.id + ' is said to be \'' + this.data.source + '\', but there\'s no source with this name found in the getMarkerInfoURL object');
					}
				}else{
					// no source given for this marker. check baseMarkerURL
					if(typeof(this.ugmo_.settings.baseMarkerInfoURL) == 'string'){
						if(this.ugmo_.settings.getMarkerInfoURL.hasOwnProperty(this.ugmo_.settings.baseMarkerInfoURL)){
							url = this.ugmo_.settings.getMarkerInfoURL[this.ugmo_.settings.baseMarkerInfoURL];
						}
					}else{
						// no baseMarkerURL specified
						throw('base URL to fetch markerInfo from was not specified! (settings.baseMarkerInfoURL)');
					}
				}
				break;
			case 'string':
				// only one url for markerInfo specified
				url = this.ugmo_.settings.getMarkerInfoURL;
				break;		
		}
			
		var requestData = {
			source: this.data.source,
			id: this.data.id
		};
		
		//create marker_ for use in the ajax request
		var marker_ = this;
		
		//do the request
		$.ajax({
            url: url,
            dataType: 'json',
            data: requestData,
            success: function(data){
                marker_.markerInfo = data.markerInfo;
				
                if(callbackFunction){
					callbackFunction.apply(marker_, [data]);
                }else{
                    marker_.showMarkerInfo(data);
                }
            },
            error: function() {
                //throw won't work here
                console.warn("selectMarker function did not receive correct (or any) data from server!");
            }
        });
	},
	
	/**
    This method is called with the information from the server retrieved by selectMarker
    @param {Object} data Data from the server
    */ 
	showMarkerInfo: function(data){
		
	  if(!data.markerInfo || typeof data.markerInfo != 'object'){
	    throw("showMarkerInfo requires markerInfo-object in data, non found!");
	  }
	  
	  var html	= data.markerInfo.html;
        
	  var infoWindowOptions = {
	    content: html,
	    position: this.markerLatLon
	  };
		
	  if(this.ugmo_.activeInfowindow !== null){
	    this.ugmo_.activeInfowindow.close();
	  }
	  
	  this.infoWindow = this.ugmo_.activeInfowindow = new google.maps.InfoWindow(infoWindowOptions);
	  
	  // check if we're in street view
	  if(this.ugmo_.sv === null){
            this.ugmo_.sv = this.ugmo_.map.getStreetView();
	  }
		  
	  //open the info window
	  if(this.ugmo_.sv.getVisible()){
	    this.infoWindow.open(this.ugmo_.sv);
	  }else{
	    this.infoWindow.open(this.ugmo_.map);
	  }
	},
	
	/**
    Let UGMO switch from map to Street View mode at the location of this marker.
    If the fields yaw, pitch or zoom are set in the UGMOMarker.markerInfo field, that information is used.
    @param {Object} data Data from the server
    */ 
	switchToStreetView: function(){
	    //check if there already is a sv interface
	    if(this.ugmo_.sv === null){
            this.ugmo_.sv = this.ugmo_.map.getStreetView();
        }
        
        if(this.markerInfo.yaw !== undefined || this.markerInfo.pitch !== undefined || this.markerInfo.zoom !== undefined){
            var pov = {
                heading: parseFloat(this.markerInfo.yaw),
                pitch: parseFloat(this.markerInfo.pitch),
                zoom: parseFloat(this.markerInfo.zoom)
            };
        }
        
        //go to streetView
        this.ugmo_.sv.setPosition(this.markerLatLon);
        
        if(pov !== undefined){
            this.ugmo_.sv.setPov(pov);
        }
        
        this.ugmo_.sv.setVisible(true);
	},
	
	/**
    Switch back to map from Street View.
    */
	switchToMap: function(){
	    this.ugmo_.showMap();
	},
	
	checkStreetViewAvailable: function(callback){
	    if(this.ugmo_.svService === null){
	        this.ugmo_.svService = new google.maps.StreetViewService();
	    }
	    
        this.ugmo_.svService.getPanoramaByLocation(this.markerLatLon, null, function(data, status){
            if(status == "OK"){
                callback(true);
            }else{
                callback(false);
            }
        });

	}
	
};

var UGMOIcon = function(ugmo_, iconData){
    return new UGMOIcon.fn.init(ugmo_, iconData);
};

UGMOIcon.fn = UGMOIcon.prototype = {
    /** @lends UGMOIcon# */
    
	/**
    Intitialize UGMOIcon
    @class
    @constructs
    @param {UGMO} ugmo_ Reference to the ugmo-instance this marker belongs to.
    @param {Object} iconData Object with icon info from the server.
    */  
    init: function(ugmo_, iconData){
        this.data = iconData;
                    
        // check if icon was already used before
        if( typeof ugmo_.icons[this.data.id] === "undefined" ){
            
            //perform some checks on the settings of the icon
            if(!this.data.image || typeof(this.data.image) !== 'string' || this.data.image.length === 0){
                throw('image property of icon "' + this.data.id + '" needs the be a string with the path to the icon image!');
            }
            if(!this.data.iconSize || typeof(this.data.iconSize) !== 'object' || this.data.iconSize.length != 2 || this.data.iconSize[0] === null || isNaN(this.data.iconSize[0]) || this.data.iconSize[1] === null || isNaN(this.data.iconSize[1])){
                throw('iconSize property of icon "' + this.data.id + '" needs to be an array with two numbers!');
            }
            if(!this.data.iconAnchor || typeof(this.data.iconAnchor) !== 'object' || this.data.iconAnchor.length != 2 || isNaN(this.data.iconAnchor[0]) || this.data.iconAnchor[0] === null || isNaN(this.data.iconAnchor[1]) || this.data.iconAnchor[1] === null){
                throw('iconAnchor property of icon "' + this.data.id + '" needs to be an array with two numbers!');
            }
        
            // no, add to icons array
            this.icon 					= new google.maps.MarkerImage(
										this.data.image,
										new google.maps.Size(this.data.iconSize[0], this.data.iconSize[1]), 
										new google.maps.Point(0, 0), 
										new google.maps.Point(this.data.iconAnchor[0], this.data.iconAnchor[1])
									);
									
            if(this.data.shadow !== undefined){		
                if(this.data.shadowAnchor === undefined){
                    this.data.shadowAnchor = [0,0];
                }
                this.shadow 				= new google.maps.MarkerImage(
                                            this.data.shadow,
                                            new google.maps.Size(this.data.shadowSize[0], this.data.shadowSize[1]), 
                                            new google.maps.Point(0, 0), 
                                            new google.maps.Point(this.data.shadowAnchor[0], this.data.shadowAnchor[1])
                                        );
            }else{
                this.shadow                 = null;
            }
                                        
            return(this);
                
        }
    }
};

UGMO.fn.init.prototype = UGMO.fn;
UGMOMarker.fn.init.prototype = UGMOMarker.fn;
UGMOIcon.fn.init.prototype = UGMOIcon.fn;
