// see http://www.howtocreate.co.uk/tutorials/javascript/objects
function FMap(mapId, opts) {

	// variables

	//argument checking
	this._mapId = (mapId == null) ? "map" : mapId;

	this._center = (opts.center == null) ? new google.maps.LatLng(40.6330, 22.94510) : opts.center;
	this._zoom = (opts.zoom == null) ? 16 : opts.zoom;

	this._singledraw = (opts.singledraw == null) ? false : opts.singledraw;
	this._domSaveId = (opts.domSaveId == null) ? null : opts.domSaveId;

	this.map;
	this.markers = new Array();
	
	this.initialize = function () { 

		var mapDiv = document.getElementById(this._mapId);
		var myOptions = {
			center: this._center,
			zoom: this._zoom,
			mapTypeId: google.maps.MapTypeId.ROADMAP,
			draggableCursor: 'move', 
			draggingCursor: 'move'
		}

		this.map = new google.maps.Map(mapDiv, myOptions);

		if (this._singledraw)
		{
			this.addMarker(this._center, null, null, {draggable:true});
		}

	};


	this.addControl = function (ctrlName, opts) {

		switch (ctrlName) {
			case 'SEARCH':

				var searchControlDiv = document.createElement('DIV');
				var searchControl = new SearchControl(searchControlDiv, this);

				searchControlDiv.index = 1;
				this.map.controls[google.maps.ControlPosition.BOTTOM].push(searchControlDiv);

				break;
			case 'DRAWTOOLS':

				var drawToolsControlDiv = document.createElement('DIV');
				var drawToolsControl = new DrawToolsControl(drawToolsControlDiv, this);

				drawToolsControlDiv.index = 2;
				this.map.controls[google.maps.ControlPosition.BOTTOM].push(drawToolsControlDiv);

				break;

			case 'CATEGORIES':

				var categoriesControlDiv = document.createElement('DIV');
				var categoriesControl = new CategoriesControl(categoriesControlDiv, this);

				categoriesControlDiv.index = 3;
				this.map.controls[google.maps.ControlPosition.RIGHT].push(categoriesControlDiv);

				break;
		}
	};

	this.addMarker = function (latlng, id, categoryId, opts) {

		var marker = new FMarker(this, latlng, id, categoryId, opts);

		this.markers.push(marker);
	}

	this.save = function() {
		if (this._domSaveId != null)
		{
			document.getElementById(this._domSaveId).value = "";
			itemsToSave = new Array();
			for (var i=0;i < this.markers.length ; i++)
			{
				itemsToSave.push( {lat: this.markers[i].marker.getPosition().lat(), lng: this.markers[i].marker.getPosition().lng()} );
			}
			document.getElementById(this._domSaveId).value = $.toJSON(itemsToSave)
		}
	}

	this.loadPoints = function(markersToLoad) {
		if (this._singledraw)
		{
			var res = markersToLoad[0].geodata;
			var latlng = new google.maps.LatLng(res[0].lat, res[0].lng);
			this.markers[0].marker.setPosition(latlng);
			this.map.setCenter(latlng);
		}
		else {
			for (var i=0;i < markersToLoad.length ; i++)
			{
				// add the marker if not exists
				if (!this.markerExists( markersToLoad[i].id ))
				{
					//res = $.evalJSON(markersToLoad[i].geodata);
					res = markersToLoad[i].geodata;
					this.addMarker(new google.maps.LatLng(res[0].lat, res[0].lng), markersToLoad[i].id, markersToLoad[i].category_id, {draggable:false, icon:markersToLoad[i].icon});
				}
			}
		}
		this.save();
	}

	this.markerExists = function(markerId) {
		for (var i=0;i < this.markers.length ; i++) {

			if (this.markers[i]._id == markerId)
			{
				return true;
			}
		}
		return false;
	}

	this.loadCategoryPoints = function(categoryId) {

		currentObj = this;

		$.getJSON('./points/index', {categoryid: categoryId }, function(data) { 
			currentObj.loadPoints(data);
		});

	}

	this.unloadCategoryPoints = function(categoryId) {

		currentObj = this;

		$.getJSON('./points/index', {categoryid: categoryId }, function(data) { 
			for (var i=0; i < data.length ;i++ ) {
				for (var j=0;j < currentObj.markers.length ; j++) {

					if (currentObj.markers[j]._categoryid == data[i].category_id) {
						currentObj.markers[j].remove({});
						currentObj.markers.splice(j,1);
					}
				}
			}
		});
	}

	this.initialize();

}


function FMarker(fmap, latlng, id, categoryId, opts) {
	draggable = (opts.draggable == null) ? false : opts.draggable;
	icon = (opts.icon == null) ? null : opts.icon;
	shadow = (opts.icon == null) ? null : './img/shadow.png';


	// marker metadata
	this._fmap = fmap;
	this._map = fmap.map;
	this._id = id;
	this._categoryid = categoryId;
	this._infowindow;
	this._infobox;

	this.marker = new google.maps.Marker({
		map: this._map, 
		position: latlng,
		draggable: draggable,
		icon: icon,
		shadow: shadow
	});

	var currentObject = this;

	google.maps.event.addDomListener(this.marker, 'click', function(event) {
		/*
		if (!currentObject._fmap._singledraw)
		{
			//open the info window (if does not already exist)
			if (currentObject._infowindow == null) { currentObject.openInfoWindow() }
		}
		*/
	});

	google.maps.event.addDomListener(this.marker, 'rightclick', function(event) {
		/*
		currentObject.remove({confirm:true})
		*/
	});

	google.maps.event.addDomListener(this.marker, 'click', function(event) {

		if (!currentObject._fmap._singledraw)
		{
			$.get('./points/view/' + currentObject._id, function(data) {

				if (currentObject._infobox == null)
				{
					var myOptions = {
							content: data,
							disableAutoPan: false,
							maxWidth: 0,
							pixelOffset: new google.maps.Size(-175, 0),
							zIndex: null,
							boxStyle: { 
								background: "url('http://www.garylittle.ca/map/artwork/tipbox.gif') no-repeat", 
								width: "350px"
							},
							closeBoxMargin: "10px 10px 2px 2px",
							closeBoxURL: "http://www.google.com/intl/en_us/mapfiles/close.gif",
							infoBoxClearance: new google.maps.Size(1, 1),
							isHidden: false,
							pane: "floatPane",
							enableEventPropagation: false
					};

					currentObject._infobox = new InfoBox(myOptions);
					currentObject._infobox.open(currentObject._map, currentObject.marker);
					
					google.maps.event.addDomListener(currentObject._infobox, 'closeclick', function(event) {
						currentObject._infobox.close();
						currentObject._infobox = null;
					});

				}

			});
		}
	});


	google.maps.event.addDomListener(this.marker, 'dragend', function(event) {
		currentObject._fmap.save();
	});

	this.openInfoWindow = function(id) {
		// retrieve form data by id
		$.get('infowindow_add.htm', function(data) {

			currentObject._infowindow = new google.maps.InfoWindow({content:data, maxWidth: 400, position: currentObject.marker.getPosition()});
			currentObject._infowindow.open(currentObject._map, currentObject.marker);

			google.maps.event.addDomListener(currentObject._infowindow, 'closeclick', function(event) {
				currentObject._infowindow = null;
			});

		});
	}

	this.remove = function(opts) {
		
		confirmation = (opts.confirm == null) ? false : opts.confirm;
		
		if (!this._fmap._singledraw)
		{
			remove = true;
			// prompt confirmation message
			if (confirmation)
			{
				remove = confirm("Are you sure you want to delete ?")
			}
			if (remove)
			{
				// then remove
				// 1. database row

				// 2. the infowindow (if any)
				if (this._infowindow != null) { this._infowindow.close() }

				// 3. the marker
				this.marker.setMap(null);
			}
		}
	}

	//this.openInfoWindow();
}

/**** CONTROLS ****/
/**
 * The SearchControl adds a search bar control to the map
 */
function SearchControl(controlDiv, fmap) {

	// We set up a variable for this since we're adding
	// event listeners later.
	var currentControl = this;
	this.fmap = fmap;

	// Set CSS styles for the DIV containing the control
	// Setting padding to 5 px will offset the control
	// from the edge of the map
	controlDiv.style.padding = '5px';

	// Set CSS for the control border
	var searchBarWrapper = document.createElement('DIV'); 
	searchBarWrapper.style.borderStyle = 'solid';
	searchBarWrapper.style.borderWidth = '3px';
	searchBarWrapper.style.borderColor = '#53A0DF';
	searchBarWrapper.style.backgroundColor = '#fff';
	controlDiv.appendChild(searchBarWrapper);

	// Set CSS for the control interior
	var searchBarInput = document.createElement('INPUT');
	searchBarInput.setAttribute('name', 'search');
	searchBarInput.setAttribute('id', 'search');
	searchBarInput.setAttribute('type', 'text');

	searchBarInput.style.fontFamily = 'Verdana,Tahoma,Arial,sans-serif';
	searchBarInput.style.fontSize = '12px';
	searchBarInput.style.paddingLeft = '4px';
	searchBarInput.style.paddingRight = '4px';
	searchBarInput.style.margin = '4px';
	searchBarInput.style.width = '250px';

	searchBarWrapper.appendChild(searchBarInput);

	// Set CSS for the control interior
	var searchBarButton = document.createElement('INPUT');
	searchBarButton.setAttribute('name', 'bsearch');
	searchBarButton.setAttribute('type', 'button');
	searchBarButton.setAttribute('value','search');

	searchBarButton.style.fontFamily = 'Verdana,Tahoma,Arial,sans-serif';
	searchBarButton.style.fontSize = '12px';
	searchBarButton.style.marginLeft = '10px';
	searchBarButton.style.margin = '4px';
	searchBarButton.style.width = '65px';

	searchBarWrapper.appendChild(searchBarButton);

	// Setup the click event listener for Home:
	// simply set the map to the control's current home property.
	google.maps.event.addDomListener(searchBarButton, 'click', function() {
		searchTerm = document.getElementById('search').value;
		currentControl.showAddress(searchTerm);
	});


	this.showAddress = function(searchTerm) {

		var geocoder = new google.maps.Geocoder();

		var currentControl = this;

		if (!geocoder) {
			alert(MapMessage.geocoderErrorText);
			return;
		}

		//geocoder.geocode(new google.maps.GeocoderRequest(searchTerm), onGeocodingFinished)
		geocoder.geocode( { 'address': searchTerm}, function(results, status) {

			if (status == google.maps.GeocoderStatus.OK) {
				
				// everything was ok - process the results
				if (currentControl.fmap._singledraw)
				{
					currentControl.fmap.markers[0].marker.setPosition( results[0].geometry.location );
					currentControl.fmap.map.setCenter(results[0].geometry.location);

					currentControl.fmap.save();
				}
				else {

					var resultBounds = new google.maps.LatLngBounds();
					for (var i = 0; i < results.length; i++)
					{
						currentControl.fmap.map.setCenter(results[i].geometry.location);
						var marker = new google.maps.Marker({
							map: currentControl.fmap.map, 
							position: results[i].geometry.location
						});

						resultBounds.union(results[i].geometry.bounds);
					}
					currentControl.fmap.map.setCenter(resultBounds.getCenter());
					currentControl.fmap.map.setZoom(currentControl.fmap._zoom);
				}
			}
			else if (status == google.maps.GeocoderStatus.ZERO_RESULTS) {
				//no results found!
				alert('no results found');
			}
			else {
				//error occured! Handle it..
				alert('an error occured, please try later');
			}
		});
	}
}


/**
 * The HomeControl adds a control to the map that
 * returns the user to the control's defined home.
 */

function DrawToolsControl(controlDiv, fmap) {

	// We set up a variable for this since we're adding
	// event listeners later.
	var currentControl = this;
	this.fmap = fmap;

	// Set CSS styles for the DIV containing the control
	// Setting padding to 5 px will offset the control
	// from the edge of the map
	controlDiv.style.padding = '5px';

	// Set CSS for the control border
	var drawToolsWrapper = document.createElement('DIV'); 
	drawToolsWrapper.style.borderStyle = 'solid';
	drawToolsWrapper.style.borderWidth = '3px';
	drawToolsWrapper.style.borderColor = '#53A0DF';
	drawToolsWrapper.style.backgroundColor = '#fff';
	controlDiv.appendChild(drawToolsWrapper);

	// Set CSS for the control interior
	var markerButton = document.createElement('INPUT');
	markerButton.setAttribute('name', 'search');
	markerButton.setAttribute('id', 'search');
	markerButton.setAttribute('type', 'button');
	markerButton.setAttribute('value', 'marker');

	markerButton.style.fontFamily = 'Verdana,Tahoma,Arial,sans-serif';
	markerButton.style.fontSize = '12px';
	markerButton.style.paddingLeft = '4px';
	markerButton.style.paddingRight = '4px';
	markerButton.style.margin = '4px';
	markerButton.style.width = '80px';

	drawToolsWrapper.appendChild(markerButton);

	// Set CSS for the control interior
	var navigateButton = document.createElement('INPUT');
	navigateButton.setAttribute('name', 'search');
	navigateButton.setAttribute('id', 'search');
	navigateButton.setAttribute('type', 'button');
	navigateButton.setAttribute('value', 'navigate');

	navigateButton.style.fontFamily = 'Verdana,Tahoma,Arial,sans-serif';
	navigateButton.style.fontSize = '12px';
	navigateButton.style.paddingLeft = '4px';
	navigateButton.style.paddingRight = '4px';
	navigateButton.style.margin = '4px';
	navigateButton.style.width = '80px';

	drawToolsWrapper.appendChild(navigateButton);

	// Setup the click event listener for Home:
	// simply set the map to the control's current home property.
	google.maps.event.addDomListener(markerButton, 'click', function(event) {
		currentControl.fmap.map.setOptions({ draggableCursor: 'crosshair', draggingCursor: 'crosshair'});

		currentControl.clickListener = google.maps.event.addDomListener(currentControl.fmap.map, 'click', function(event) {
			// add markers here
			currentControl.fmap.addMarker(event.latLng, null, null, {draggable: true});

			// and reset the cursor to navigation
			currentControl.resetCursor();
		});

	});

	// Setup the click event listener for Home:
	// simply set the map to the control's current home property.
	google.maps.event.addDomListener(navigateButton, 'click', function(event) {

		this.resetCursor();

	});


	this.resetCursor = function() {

		if (this.clickListener != null) { google.maps.event.removeListener(this.clickListener); }

		this.fmap.map.setOptions({ draggableCursor: 'move', draggingCursor: 'move'});

	}

}


/**
 * The HomeControl adds a control to the map that
 * returns the user to the control's defined home.
 */

function CategoriesControl(controlDiv, fmap) {

	// We set up a variable for this since we're adding
	// event listeners later.
	var currentControl = this;
	this.fmap = fmap;

	// Set CSS styles for the DIV containing the control
	// Setting padding to 5 px will offset the control
	// from the edge of the map
	controlDiv.style.padding = '5px';

	controlDiv.style.margin = '5px';

	controlDiv.style.overflow = 'scroll';

	controlDiv.style.width = '230px';

	controlDiv.style.opacity = '0.8';

	controlDiv.style.height = '70%';

	controlDiv.style.backgroundColor = '#fff';

	controlDiv.style.border = '1px solid #ccc';

	$.get('./categories/index', function(data) {
		controlDiv.innerHTML = data;
	});
}
