google.load("maps", "2.x");
google.setOnLoadCallback(initMap);

window.addEvent('siteready', function() {
	initMapEngine();
} );

window.addEvent('unload', function() {
	new google.maps.Unload();
} );

function initMapEngine()
{
	// initialize map engine
	m = new mapEngine();
	m.initBlock( s.body );
	document.addEvent('updateblock', function(obj) {
		m.initBlock( obj );
	} );
}

function initMap()
{
	if (s)
	{
		initObjects();
		m.init();
		document.fireEvent('prestartedmap');
		document.fireEvent('startedmap');
	}
	else
		initMap.delay(100);
}

function mapEngine()
{
	this.init = function()
	{
		this.maps = new Array();
		// actions
		document.addEvent("keydown", function(event) {
			this.keyPressed( event );
		}.bind(this) );
		
		var objs = document.getElements('.exec');
		for (var i=0; i<objs.length; i++)
		{
			objs[i].importProps();
			if (objs[i].hasClass('info'))			this.infoTrip(objs[i]);
		}
		//
		var map = $('map');
		if (map)
			this.addMap( map );
	},
	
	this.initBlock = function( obj )
	{
		var objs = obj.getElements('.exec');
		objs[objs.length] = obj;
		for (var i=0; i<objs.length; i++)
		{
			objs[i].importProps();
			if (objs[i].hasClass('draw'))			this.drawOnMap(objs[i]);
			//if (objs[i].hasClass('info'))			this.infoTrip(objs[i]);
			if (objs[i].hasClass('searchmap'))		this.searchMap(objs[i]);
			if (objs[i].hasClass('map-photos'))		this.photosMap(objs[i]);
			if (objs[i].hasClass('map-banner'))		this.bannerMap(objs[i]);
			if (objs[i].hasClass('map-zoom'))		this.zoomMap(objs[i]);
			if (objs[i].hasClass('map-resize'))		this.resizeMap(objs[i]);
			if (objs[i].hasClass('map-view'))		this.changeViewMode(objs[i]);
			if (objs[i].hasClass('map-fullscreen'))	this.fullscreenMap(objs[i]);
		}
	},
	
	this.addMap = function( obj )
	{
		obj.importProps();
		var options = {
			'view': obj.view,
			'center': obj.center,
			'lat': obj.lat,
			'lng': obj.lng,
			'zoom': obj.zoom,
			'sw': { 'lat': obj.sw_lat, 'lng': obj.sw_lng },
			'ne': { 'lat': obj.ne_lat, 'lng': obj.ne_lng },
			'background': obj.background
		};
		obj.map = new Map( obj, options );
		if (obj.mode)
			obj.map.mode(obj.mode);
		this.maps[ this.maps.length ] = obj.map;
	},
	
	this.addPanel = function( panel, options )
	{
		var panel = new Panel( $('map'), panel, options );
		return panel;
	},
	
	this.keyPressed = function( event )
	{
		for (var i=0; i<this.maps.length; i++)
		{
			if (this.maps[i].mouseIsOver)
			{
				switch (event.key)
				{
					case 'delete':
						this.maps[i].launchRemove();
					break;
				}
			}
		}
	},
	
	this.infoTrip = function( obj )
	{
		document.addEvent('prestartedmap', function(obj) {
			obj.targetMap = $(obj.targetEl);
			var map = obj.targetMap.map;
			map._infos[map._infos.length] = obj;
		}.pass(obj, this) );
	},
	
	this.searchMap = function( obj )
	{
		obj.form = obj.getElement('form');
		obj.search = obj.getElement('.search');
		obj.button = obj.getElement('.go-search');
		if (obj.suggest)
		{
			obj.search.icon = new Element('a', {'class': 'icon ghost', 'href': 'javascript:;'}).inject( obj.search, 'before' )
			obj.search.icon.addEvent('click', this.cancelPreSearchMap.pass(obj, this) );
			
			obj.search.addEvent('keyup', function(search) {
				if (search.get('value').length > 0)
					search.icon.removeClass('ghost');
				else
					search.icon.addClass('ghost');
				if (this.timerPreSearchMap) $clear(this.timerPreSearchMap);
				this.timerPreSearchMap = this.preSearchMap.delay(500, this, search);
			}.pass(obj.search, this) );
			obj.search.addEvent('focus', function(search) {
				this.openPreSearchMap(search);
			}.pass(obj.search, this) );
			obj.search.addEvent('blur', function(search) {
				this.closePreSearchMap(search);
			}.pass(obj.search, this) );
		}
		var fn = function(obj) {
			obj.button.targetMap = $(obj.targetEl);
			obj.button.targetMap.map.search( obj.search.get('value') );
		}.pass(obj, this);
		if (obj.form)
		{
			obj.form.addEvent('submit',  fn );
			obj.form.addEvent('submit',  function(event) { new Event(event).stop(); } );
		}
		obj.button.addEvent('click',  fn );
		obj.button.addEvent('click',  function(event) { new Event(event).stop(); } );
	},
	
	this.preSearchMap = function( search )
	{
		if (search.get('value').length >= 3)
		{
			search.icon.addClass('loading');
			if (search.preSearchXHR)
				search.preSearchXHR.cancel();
			search.preSearchXHR = new Request( {
				url: 'ajax.php',
				data: "load=module&name=presearch&q=" + search.get('value'),
				method: "get"
			} ).send();
			search.preSearchXHR.addEvent('onComplete', this.parsePreSearchMap.pass(search, this) );
		}
		else
		{
			this.closePreSearchMap( search )
		}
	},
	
	this.parsePreSearchMap = function( search )
	{
		search.icon.removeClass('loading');
		search.results.set('html', search.preSearchXHR.response.text);
		this.openPreSearchMap(search);
	},
	
	this.createPreSearchMap = function( search )
	{
		var searchPos = search.getCoordinates();
		search.results = new Element('div', {'class': 'search-results'} )
			.setStyles({'position': 'absolute', 'zIndex': 2000, 'left': searchPos.left, 'top': (searchPos.top + searchPos.height), 'width': searchPos.width })
			.inject(document.body);
		search.results.fx = new Fx.Tween(search.results, { 'property': 'opacity' });
	}
	this.openPreSearchMap = function( search )
	{
		if (!search.results)
			this.createPreSearchMap( search );
		if (search.get('value').length >= 3)
			search.results.fx.start(1);
	},
	
	this.closePreSearchMap = function( search )
	{
		search.results.fx.start(0);
	},
	
	this.cancelPreSearchMap = function( obj )
	{
		if (this.timerPreSearchMap) 	$clear(this.timerPreSearchMap);
		if (obj.search.preSearchXHR) 	obj.search.preSearchXHR.cancel();
		obj.search.icon.removeClass('loading');
		obj.search.icon.addClass('ghost');
		obj.search.set('value', '');
		obj.search.results.fx.start(0);
	},
	
	this.photosMap = function( obj )
	{
		document.addEvent('startedmap', function(obj) {
			obj.panel = this.addPanel( obj, { 'position': 'left', 'closeCSS': 'photo-panel_close', 'overflow': 'hidden', 'open': obj.open } );
			obj.panel.addEvent('resizing', this.resizePhotosMap.pass(obj,this) );
		}.pass(obj, this) );
		obj.content = new Element('div').inject( obj );
		
		document.addEvent('startedmap', function(obj) {
			obj.map = $(obj.targetEl).map;
			var func = function(obj) {
				if (obj.panel.selected)
				{
					obj.loading(1);
					if (obj.updateTimer)
						$clear( obj.updateTimer );
					obj.updateTimer = this.launchPhotoMap.delay(1000, this, obj);
				}
			}.pass(obj, this);
			var defunc = function(obj) {
				if (obj.updateTimer)
					$clear( obj.updateTimer );
				if (obj.execXHR)
					obj.execXHR.cancel();
				obj.map.cleanPois();
			}.pass(obj, this);
			obj.map.addEvent('resized', func );
			obj.map.addEvent('moveend', func );
			obj.map.addEvent('changezoom', func );
			obj.panel.addEvent('focus', func );
			obj.panel.addEvent('blur', defunc );
		}.pass(obj, this) );
	},
	
	this.resizePhotosMap = function( obj )
	{
		var size = $('map').getSize();
		if (obj.getElement('.photo-main'))
			obj.getElement('.photo-main').setStyle('height', size.y - 88 );
	},
	
	this.launchPhotoMap = function( obj )
	{
		var bounds = obj.map.getBounds();
		if (obj.execXHR)
			obj.execXHR.cancel();
		obj.execXHR = new Request( {
			url: obj.url + '&area='+bounds.sw.lat+' '+bounds.sw.lng+','+bounds.ne.lat+' '+bounds.ne.lng,
			autoCancel: true,
			method: "post"
		} ).send();
		obj.execXHR.addEvent('onComplete', this.addPhotosMap.pass(obj, this) );
	},
	
	this.addPhotosMap = function( obj )
	{
		obj.content.set( 'html', obj.execXHR.response.text );
		this.resizePhotosMap( obj );
		document.fireEvent('updateblock', obj.content );
		obj.loading(0);
	},
	
	this.bannerMap = function( obj )
	{
		document.addEvent('startedmap', function(obj) {
			obj.panel = this.addPanel( obj, { 'position': 'left', 'closeCSS': 'banner-panel_close', 'open': obj.open } );
		}.pass(obj, this) );
	},
	
	this.zoomMap = function( obj )
	{
		obj.input = obj.getElement('input');
		obj.empty();
		obj.container = new Element('div', {'class': 'map-zoom-containr'}).inject(obj);
		obj.slider = new Element('div', {'class': 'map-zoom-slider'}).inject(obj.container);
		obj.knob = new Element('div', {'class': 'map-zoom-knob'}).set('html','&nbsp;').inject(obj.slider);
		obj.zoomslider = new Slider( obj.slider, obj.knob, { snap: true, steps: 13 } );
		obj.zoomPrev = new Element('div', {'class': 'map-zoom-prev'}).set('html','&nbsp;').addEvent('click', this.zoomMapStep.pass([obj,-1], this) ).inject(obj.container, 'top');
		obj.zoomNext = new Element('div', {'class': 'map-zoom-next'}).set('html','&nbsp;').addEvent('click', this.zoomMapStep.pass([obj,1], this) ).inject(obj.container, 'bottom');
		
		document.addEvent('startedmap', function(obj) {
			obj.map = $(obj.targetEl).map;
			obj.zoomslider.set( obj.map.getZoom() );
			obj.zoomslider.addEvent('onComplete', obj.map.changeZoom.bind(obj.map) );
			obj.map.addEvent('changezoom', function(obj) {
				obj.zoomslider.set( obj.map.getZoom() );
			}.pass(obj, this) );
			var saved = obj.map.savedPosition();
			if (saved)
			{
				obj.map.back = new Element('a', {'href': 'javascript:;', 'class': 'map-back'}).set('html', '<span>Torna alla posizione precedente</span>').inject(obj, 'top');
				obj.map.back.addEvent('mouseenter', function() { s.addMouseTip( 'Torna all\'ultima posizione della mappa', 0 ); } );
				obj.map.back.addEvent('mouseleave', function() { s.closeMouseTip( ); } );
				obj.map.back.addEvent('click', function(obj,saved) { obj._map.setCenter( saved.center, saved.zoom ); }.pass([obj.map, saved], this) );
				
			}
		}.pass(obj, this) );
	},
	
	this.zoomMapStep = function( obj, offset )
	{
		var current = obj.map.getZoom();
		obj.map.changeZoom(current+offset);
	},
	
		
	this.drawOnMap = function( obj )
	{
		obj.target = $(obj.targetEl)
		if (obj.target)
		{
			obj.dd = new DragDrop( obj, obj.target );
			obj.dd.addEvent('drop', function( obj ) {
				switch (obj.type)
				{
					case 'trip': obj.target.map.loadTrip( obj.tid ); break;
					case 'zone': obj.target.map.loadZone( obj.zid ); break;
				}
			}.pass(obj, this) );
		}
	},
	
	this.resizeMap = function( obj )
	{
		obj.target = $(obj.targetEl);
		obj.resize = new Drag($(obj.targetEl), {
			handle: obj,
			modifiers: {'x': null, 'y': 'height'}
		} );
		obj.resize.addEvent('onDrag', function(obj) {
			if (obj.target.getSize().y < 300)
				obj.target.setStyle('height', 300);
			obj.target.map.fireEvent('resizing');
		}.pass(obj, this) );
		obj.resize.addEvent('onComplete', function(obj) {
			obj.target.map.checkResize();
			obj.target.map.fireEvent('resized');
		}.pass(obj, this) );
	},
	
	this.fullscreenMap = function( obj )
	{
		document.addEvent('startedmap', function(obj) {
			obj.el = $(obj.targetEl);
			obj.top = $(obj.targetTop);
			obj.bottom = $(obj.targetBottom);
			obj.mapbox = $(obj.targetMap);
			obj.map = obj.mapbox.map;
			obj.fullscreen = obj.getElement('input.radio');
			obj.fn = function(obj) {
				this.fullscreenResize(obj);
			}.pass(obj, this);
			
			obj.esize = obj.el.getSize();
			obj.msize = obj.mapbox.getSize();
			
			obj.fullscreen.addEvent('change', function(obj) {
				if (obj.fullscreen.get('checked'))
				{
					// backup
					this.fullscreenResize(obj);
					window.addEvent('resize', obj.fn );
				}
				else
				{
					obj.el.setStyles({'position': '', 'height': obj.esize.y}).inject( $('desk') );
					obj.mapbox.setStyles({'height': obj.msize.y});
					obj.map.checkResize();
					window.removeEvent('resize', obj.fn );
				}
			}.pass(obj, this) );
		}.pass(obj, this) );
	},
	
	this.fullscreenResize = function( obj )
	{
		var size = document.getSize();
		var tsize = obj.top.getSize();
		var bsize = obj.bottom.getSize();
		obj.el.setStyles({'position': 'absolute', 'width': '100%', 'height': size.y, 'top': 0, 'left': 0}).inject( document.body );
		obj.mapbox.setStyles({'height': size.y - tsize.y - bsize.y});
		obj.map.checkResize();
	},
	
	this.changeViewMode = function( obj )
	{
		document.addEvent('startedmap', function(obj) {
			obj.map = $(obj.targetEl).map;
			var views = obj.getElements('input.radio');
			for (var i=0; i<views.length; i++)
			{
				views[i].addEvent('change', function(obj, view) {
					obj.map.changeView( view.get('value') );
				}.pass([obj,views[i]], this) );
			}
		}.pass(obj, this) );
	}
}

var Map = new Class({
	initialize: function(el, options){
		this._el = el;
		this._options = options;
		this._opacity_tween = {'from': 0, 'to': .5};
		
		this.plugins = new Array();
		this._infos = new Array();
		this._loops = new Array;
		
		this._pois = new Array;
		this._trips = new Array;
			this._cacheTrips = new Array();
		this._zones = new Array;
		
		this.firstMapMove = true;
		
		this.initMap(this._options.center, {
			'view': this._options.view,
			'sw': { 'lat': this._options.sw.lat, 'lng': this._options.sw.lng }, 
			'ne': { 'lat': this._options.ne.lat, 'lng': this._options.ne.lng },
			'point': { 'lat': this._options.lat, 'lng': this._options.lng, 'zoom': this._options.zoom }
		} );
		
		google.maps.Event.addListener(this._map, "mousemove", function(latlng) {
			this.mouseMove( latlng );
		}.bind(this) );
		google.maps.Event.addListener(this._map, "mouseover", function() {
			this.mouseOver( );
		}.bind(this) );
		google.maps.Event.addListener(this._map, "mouseout", function() {
			this.mouseOut( );
		}.bind(this) );
		google.maps.Event.addListener(this._map, "click", function(overlay,point) {
			this.mouseClick( point );
			return false;
		}.bind(this) );
		google.maps.Event.addListener(this._map, "move", function() {
			this.mapMove( );
		}.bind(this) );
		google.maps.Event.addListener(this._map, "moveend", function() {
			this.mapMoveEnd( );
		}.bind(this) );
		google.maps.Event.addListener(this._map, "zoomend", function() {
			this.mapZoomEnd( );
		}.bind(this) );
		
		/// add-ons
		this.createAlert();
		this.createName();
		//if (this._options.background != 'none')
		//	this.setBackground( this._opacity_tween.to );
	},
	
	initMap: function( mode, params )
	{
		this._map = new google.maps.Map2( this._el );
		if (params.view)
			this.changeView( params.view );
		//this._map.enableContinuousZoom();
		switch (mode)
		{
			case 'area':
				var bounds = new google.maps.LatLngBounds( new google.maps.LatLng(params.sw.lat, params.sw.lng), new google.maps.LatLng(params.ne.lat, params.ne.lng) );
				var center = bounds.getCenter();
				var zoom = this._map.getBoundsZoomLevel( bounds );
			break;
			case 'point':
				var center = new google.maps.LatLng(params.point.lat, params.point.lng);
				var zoom = parseInt( params.point.zoom || 6 );
			break;
			default:
				var center = new google.maps.LatLng(44.7577048448913, 10.6598281860352);
				var zoom = parseInt( params.point.zoom || 6 );
			break;
		}
		this._map.setCenter(center, zoom);
	},
	
	mapMove: function( )
	{
		this.updateBackground(this._opacity_tween.to);
	},
	
	mapMoveEnd: function( )
	{
		this._map.panTo( this._map.getCenter() );
		this.fireEvent('moveend');
		
		this.savePosition();
	},
	
	mapZoomEnd: function( )
	{
		this.fireEvent('changezoom');
		
		this.savePosition();
	},
	
	mouseClick: function( point )
	{
		if (point)
		{
			switch (this._mode)
			{
				case 'new-zone':
					var zone = this.findZone('new');
					if (!zone)
						this.addZone('new', { 'style': 'new' });
					zone.add( point, true );
				break;
				case 'new-trip':
					if (!this.newTrip)
						this.newTrip = this.addTrip('new', { 'style': 'new' } );
					this.newTrip.add( { 'point': point } );
				break;
				case 'new-poi':
					this.addPoi( point );
				break;
			}
		}
	},
	
	mouseOver: function()
	{
		this.mouseIsOver = true;
		this.updateBackground(this._opacity_tween.from);
	},
	
	mouseOut: function()
	{
		this.mouseIsOver = false;
		this.updateBackground(this._opacity_tween.to);
	},
	
	mouseMove: function( latlng )
	{
		this.currentLatLng = latlng;
		// move into map
		if (!this.draggingPath)
		{
			if (this._trips)
			{
				for (var i=0; i<this._trips.length; i++)
				{
					//this._trips[i].checkForPoint( latlng );
				}
			}
		}
	},
	
	savePosition: function( )
	{
		if (this.firstMapMove == false)
		{
			/// save position cookie
			Cookie.dispose('mappos');
			Cookie.write('mappos', this.getCenter().lat()+'|'+this.getCenter().lng()+'|'+this.getZoom() );
		}
		this.firstMapMove = false;
	},
	
	savedPosition: function( )
	{
		var saved = Cookie.read('mappos');
		if (saved)
		{
			var pts = saved.split('|');
			var obj = {
				'center': new google.maps.LatLng( pts[0], pts[1] ),
				'zoom': parseInt(pts[2])
			}
			return obj;
		}
		return false;
	},
	
	zoomBounds: function( sw, ne )
	{
		var bounds = new google.maps.LatLngBounds( sw, ne );
		var center = bounds.getCenter();
		var zoom = this._map.getBoundsZoomLevel( bounds );
		this._map.setCenter(center, zoom);
	},
	
	changeZoom: function( level )
	{
		this._map.setZoom( parseInt(level) );
	},
	
	changeView: function( mode )
	{
		var maptype = null;
		switch (mode)
		{
			case 'map': 		maptype = G_NORMAL_MAP; 	break;
			case 'satellite': 	maptype = G_HYBRID_MAP; 	break;
			case 'terrain':		maptype = G_PHYSICAL_MAP; 	break;
		}
		this._map.setMapType( maptype );
	},
	
	gotoPoint: function( lat, lng )
	{
		this._map.panTo( new google.maps.LatLng(lat,lng) );
	},
	
	getMap: function( )
	{
		return this._map;
	},
	
	getZoom: function( )
	{
		return this._map.getZoom();
	},
	
	getCenter: function( )
	{
		return this._map.getCenter();
	},
	
	getBounds: function( )
	{
		var bounds = this._map.getBounds();
		var sw = bounds.getSouthWest();
		var ne = bounds.getNorthEast();
		return { 
			'sw': { 'lat': sw.lat(), 'lng': sw.lng() },
			'ne': { 'lat': ne.lat(), 'lng': ne.lng() }
		}
	},
	
	checkResize: function( )
	{
		this._map.checkResize();
		this.fireEvent('resizing');
	},
	
	launchRemove: function( )
	{
		for (var i=0; i < this._trips.length; i++)
			this._trips[i].launchRemove();
		for (var i=0; i < this._zones.length; i++)
			this._zones[i].launchRemove();
	},
	
	selectMarker: function( marker, multiple )
	{
		for (var i=0; i < this._pois.length; i++)
			if ( (marker != this._pois[i].marker) && (this._pois[i].marker.selected) )
				this._pois[i].marker.deselect();
		for (var i=0; i < this._trips.length; i++)
			this._trips[i].selectMarker(marker, multiple);
		for (var i=0; i < this._zones.length; i++)
			this._zones[i].selectMarker(marker, multiple);
	},
	
	mode: function( mode )
	{
		this._mode = mode;
	},
	
	search: function( search )
	{
		if (!this.geocoder)
			this.geocoder = new google.maps.ClientGeocoder();
		this.geocoder.getLocations(search, this.parseSearch.bind(this) );
	},
	
	parseSearch: function( response )
	{
		if (!response || response.Status.code != 200) {
			this.alert("Impossibile risolvere l'indirizzo...", 1);
		} else {
			var tabAccuracy = new Array(2,4,6,10,12,13,16,16,17);
			place = response.Placemark[0];
			var accuracy = place.AddressDetails.Accuracy;
			point = new google.maps.LatLng(place.Point.coordinates[1], place.Point.coordinates[0]);
			this._map.setCenter(point, tabAccuracy[accuracy]);
			this.fireEvent('searched', point);
			if (!this.searchPoint)
			{
				this.searchPoint = new google.maps.Marker(point);
				this._map.addOverlay(this.searchPoint);
			}
			else
				this.searchPoint.setLatLng( point );
			
			return point;
		}
	},
	
	puttedPutMap: function( mouse, params )
	{
		var mapPosition = this._el.getPosition();
		var point = new google.maps.Point(mouse.x - mapPosition.x, mouse.y - mapPosition.y);
		var putmapLatLng = this._map.fromContainerPixelToLatLng( point );
		switch (params.mode)
		{
			case 'trip':
				switch (params.action)
				{
					case 'addStop':
						var trip = this.findTrip( params.tid );
						if (trip == false)
							trip = this.addTrip(params.tid, { 'style': 'new', 'editable': 'true' } );
						trip.add( { 'point': putmapLatLng } );
						trip.build();
						if (this.loadedTrip)
							this.cleanTrip(this.loadedTrip);
					break;
					case 'moveStop':
						var trip = this.findTrip( params.tid );
						trip.move( params.index, putmapLatLng );
						trip.build();
					break;
				}
			break;
		}
	},
	
	writeInput: function( putmap, data )
	{
		putmap.input.set('value', data);
	},
	
	addLoop: function( interval, index )
	{
		this._loops[ index ] = interval;
	},
	
	addMarker: function( lat, lng )
	{
		var marker = new Point( new google.maps.LatLng(lat, lng), { 'type': 'general' } );
		this._map.addOverlay( marker );
		return marker;
	},
	
	addPoi: function( params )
	{
		var poi = new Poi( this, params );
		poi.addEvents( {
			'selected': function(poi, multiple) { this.selectMarker( poi.marker, multiple ); }.bind(this)
		} );
		if (params.details)
		{
			poi.addEvent('selected', function(poi, details) {
				poi.marker.updateTip('<img src="templates/images/icons/loading.gif" />');
				poi.xhr = new Request( { 'url': details } ).send();
				poi.xhr.addEvent('onComplete', function(poi) {
					poi.marker.updateTip(poi.xhr.response.text);
				}.pass(poi, this));
			}.pass([poi,params.details], this) );
		}
		this._pois[ this._pois.length ] = poi;
		return poi;
	},
	
	addTrip: function( id, options )
	{
		var trip = new Path( this, id, options );
		trip.addEvents( {
			'removed': function(trip) { this.fireEvent('trip-removed', trip); }.pass(trip,this),
			'changed': function(trip) { if (!trip._options.norebound) this.changedTrip(trip); this.fireEvent('trip-changed', trip); }.pass(trip, this)/*,
			'select': function(trip) { }.pass(trip, this)*/
		} );
		trip.addEvents( {
			'marker-added': function(stop, trip) { this.fireEvent('marker-added', [stop,trip]) }.bind(this),
			'marker-moved': function(stop, trip) { this.fireEvent('marker-moved', [stop,trip]) }.bind(this),
			'marker-removed': function(stop, trip) { this.fireEvent('marker-removed', [stop,trip]) }.bind(this),
			'marker-selected': function(stop, trip, multiple) { this.selectMarker( stop, multiple ); this.fireEvent('marker-selected', [stop,trip,multiple]) }.bind(this),
			'marker-geo': function(stop, trip) { this.fireEvent('marker-geo', [stop,trip]) }.bind(this)
		} );
		this.applyInfos( trip );
		this._trips[ this._trips.length ] = trip;
		
		this.fireEvent('trip-added', [this, trip]);
		
		return trip;
	},
	
	addZone: function( id, options )
	{
		var zone = new Zone( this, id, options );
		/*zone.addEvents( {
			'remove': function(zone) { }.pass(zone,this),
			'select': function(zone) { }.pass(zone, this),
			'changed': function(zone) { this.panel.changedZone( zone ); }.pass(zone, this)
		} );*/
		zone.addEvents( {
			'marker-added': function(vertex, zone) { this.fireEvent('marker-added', [vertex,zone]) }.bind(this),
			'marker-moved': function(vertex, zone) { this.fireEvent('marker-moved', [vertex,zone]) }.bind(this),
			'marker-removed': function(vertex, zone) { this.fireEvent('marker-removed', [vertex,zone]) }.bind(this),
			'marker-selected': function(vertex, zone, multiple) { this.selectMarker( vertex, multiple ); this.fireEvent('marker-selected', [vertex,zone,multiple]) }.bind(this)
		} );
		// apply recorded info
		this.applyInfos( zone );
		
		this._zones[ this._zones.length ] = zone;
		
		return zone;
	},
	
	findPoi: function( pid )
	{
		var pois = this._pois;
		for (i in pois)
		{
			if (pois[i]._id == pid)
				return pois[i];
		}
		return false;
	},
	
	findTrip: function( tid )
	{
		var trips = this._trips;
		for (i in trips)
		{
			if (trips[i]._id == tid)
				return trips[i];
		}
		return false;
	},
	
	findZone: function( zid )
	{
		var zones = this._zones;
		for (i in zones)
		{
			if (zones[i]._id == zid)
				return zones[i];
		}
		return false;
	},
	
	removePoi: function( poi )
	{
		poi.remove();
	},
	
	removeTrip: function( trip )
	{
		trip.remove( );
	},
	
	removeZone: function( zone )
	{
		zone.remove( );
	},
	
	cleanTrip: function( trip )
	{
		var trips = this._trips;
		for (var i=0; i<trip._markers.length; i++)
			trip._markers[i]._img.dispose();
		trip._markers.length = 0;
		trip.clean();
		//this.applyInfos(trip);
		this._trips.erase( trip );
		this.fireEvent('trip-removed', trip);
	},
	
	cleanZone: function( zone )
	{
		var zones = this._zones;
		for (var i=0; i<zone._markers.length; i++)
			zone._markers[i]._img.dispose();
		zone._markers.length = 0;
		zone.clean();
	},
	
	cleanPois: function( )
	{
		var pois = this._pois;
		for (i=0; i<pois.length; i++)
		{
			this.removePoi(pois[i]);
		}
	},
	
	cleanTrips: function( )
	{
		var trips = this._trips;
		for (i=0; i<trips.length; i++)
		{
			if (trips[i]._id != 'new')
			{
				this.cleanTrip(trips[i]);
			}
		}
	},
	
	loadTrip: function( tid )
	{
		if (!this.plugins['trip'])
		{
			this.plugins['trip'] = new Asset.javascript("templates/js/trip.js");
			this.plugins['trip'].addEvent('load', this.loadTrip.pass(tid, this) );
			return;
		}
		
		if (this._cacheTrips[tid])
		{
			this.viewTrip( tid,this._cacheTrips[tid] );
		}
		else
		{
			this.tripXHR = new Request( {
				url: 'request.php',
				data: 'task=trip&tid='+tid,
				method: "post"
			} ).send();
			this.tripXHR.addEvent('onSuccess', function(tid) {
				var xml = this.tripXHR.response.xml;
				this.viewTrip( tid, xml );
				this._cacheTrips[tid] = xml;
			}.pass(tid, this) );
		}
	},
	
	viewTrip: function( tid, xml ) 
	{
		if (this.loadedTrip)
			this.cleanTrip( this.loadedTrip );
		this.loadedTrip = this.addTrip( tid, { 'style': 'loaded' } );
		this.loadedTrip.loadFromXML( xml );
		this.name( this.loadedTrip.name, 0 );
		this.addEvent('trip-removed', this.closeName.bind(this) );
		//this.alert( this.loadedTrip.name, 1 );
		this.zoomBounds( this.loadedTrip.sw, this.loadedTrip.ne );
		this.fireEvent('trip-loaded');
	},
	
	changedTrip: function( trip )
	{
		var bounds = trip.getBounds();
		this.zoomBounds( bounds.sw, bounds.ne );
	},
	
	loadTripPanel: function( trip )
	{
		this.panel.load( {'mode':'trip', 'task':'new', 'points': trip.queryString()} );
	},
	
	loadZone: function( zid )
	{
		if (!this.plugins['zone'])
		{
			this.plugins['zone'] = new Asset.javascript("templates/js/zone.js");
			this.plugins['zone'].addEvent('load', this.loadZone.pass(zid, this) );
			return;
		}
		
		this.zoneXHR = new Request( {
			url: 'request.php',
			data: 'task=zone&zid='+zid,
			method: "post"
		} ).send();
		this.zoneXHR.addEvent('onSuccess', function(zid) {
			if (this.loadedZone)
				this.removeZone( this.loadedZone );
			var xml = this.zoneXHR.response.xml;
			this.loadedZone = this.addZone( zid, 'loaded' );
			this.loadedZone.loadFromXML( xml );
			this.zoomBounds( this.loadedZone.sw, this.loadedZone.ne );
		}.pass(zid, this) );
	},
	
	loadZonePanel: function( zone )
	{
		this.panel.load( {'mode':'zone', 'task':'new', 'points': zone.queryString()} );
	},
	
	applyInfos: function( obj )
	{
		for (var i=0; i<this._infos.length; i++)
		{
			var info = this._infos[i];
			switch (info.mode)
			{
				case 'trip':
					if (info.tid == obj._id)
					{
						switch (info.what)
						{
							case 'distance':
								obj.addEvent('success', function(obj, trip) { obj.set('value', trip.distance() ); }.pass([info, obj]) );
							break;
							case 'path':
								obj.setPath( info.get('value') );
								obj.addEvent('success', function(obj, trip) { obj.set('value', trip.getPath() ); }.pass([info, obj]) );
								obj.addEvent('error', function(obj, trip) { obj.set('value', '' ); }.pass([info, obj]) );
								this.addEvent('trip-removed', function(obj, trip) { obj.set('value', ''); }.pass([info, obj]) );
							break;
							case 'summary':
								obj.addEvent('success', function(obj, trip) { obj.set('value', trip.getSummary() ); }.pass([info, obj]) );
							break;
						}
					}
				break;
				case 'zone':
					if (info.zid == obj._id) {
						switch (info.what)
						{
							case 'area':
								obj.addEvent('success', function(obj, zone) {
									info.set('value', zone.area() );
								}.pass([info, obj]) );
							break;
							case 'vertex':
								obj.setPolygon( info.get('value') );
								obj.addEvent('success', function(obj, zone) { obj.set('value', zone.getPolygon() ); obj.fireEvent('change'); }.pass([info, obj]) );
							break;
						}
					}
				break;
			}
		}
	},

	createAlert: function( )
	{
		this.alertWidth = 150;
		this.alertHeight = 150;
		var size = this._el.getSize();
		var position = this._el.getPosition();
		this.alertBox = new Element('div', {'class': 'map-alert'}).set('html', '<table><tr><td id="alert-map"></td></tr></table>').setStyles({'position':'absolute', 'width': this.alertWidth, 'height': this.alertHeight, 'top': position.y + ((size.y - this.alertHeight) / 2), 'left': position.x + ((size.x - this.alertWidth) / 2) }).inject(document.body);
		this.alertContent = $('alert-map');
		this.alertContent.setStyles({'width': this.alertWidth, 'height': this.alertHeight});
		this.alertBox.fx = new Fx.Tween( this.alertBox, {'property': 'opacity'}).set( 0 );
	},
	
	alert: function( content, autoclose )
	{
		this.alertContent.set('html', content);
		if (autoclose)
		{
			this.alertBox.fx.start( 1 ).chain( function() {
				this.closeAlert.delay(1000, this);
			}.bind(this) );
		}
	},
	
	closeAlert: function( )
	{
		this.alertBox.fx.start(0);
	},
	
	createName: function( )
	{
		var size = this._el.getSize();
		var position = this._el.getPosition();
		this.nameBox = new Element('div', {'class': 'map-name'}).setStyles({'position':'absolute', 'bottom': 0, 'right': 0 }).inject(this._el);
		this.nameBox.fx = new Fx.Tween( this.nameBox, {'property': 'opacity'}).set( 0 );
	},
	
	name: function( content, autoclose )
	{
		this.nameBox.set('html', content);
		if (autoclose)
		{
			this.nameBox.fx.start( 1 ).chain( function() {
				this.closeName.delay(1000, this);
			}.bind(this) );
		}
		else
			this.nameBox.fx.start( 1 );
	},
	
	closeName: function( )
	{
		this.nameBox.fx.start(0);
	},
	
	setBackground: function(opacity)
	{
		if (opacity == null) { return; }
		if (opacity <= 0) { opacity = 0; }
		else if (opacity > 1) { opacity = opacity/100; }
		this._opacity = opacity;
		if (!this._opacityBg)
		{
			this._opacityBg = new Element('div', {'class': 'opacity-bg'}).setStyles({'position':'absolute'});
			this._opacityBg.fx = new Fx.Tween( this._opacityBg, { 'property': 'opacity' } ).set(this._opacity);
			this._map.getPane(G_MAP_MAP_PANE).appendChild( this._opacityBg );
		}
		this.updateBackground(this._opacity);
	},
	
	updateBackground: function(opacity)
	{
		if (this._map && this._opacityBg && this._opacity != null)
		{
			var screen_scale = 3;
			var map_width = this._map.getSize().width;
			var map_height = this._map.getSize().height;
			var nw = new google.maps.LatLng(this._map.getBounds().getNorthEast().lat(),this._map.getBounds().getSouthWest().lng());
			var offset = this._map.fromLatLngToDivPixel(nw);
			var left = offset.x-(map_width*((screen_scale-1)/2));
			var top = offset.y-(map_height*((screen_scale-1)/2));
			var width = screen_scale*map_width;
			var height = screen_scale*map_height;
			this._opacity = opacity;
			this._opacityBg.setStyles({'left': left, 'top': top, 'width': width, 'height': height});
			this._opacityBg.fx.cancel();
			this._opacityBg.fx.start( this._opacity );
		}
	}
});

Map.implement(new Events, new Options);

var MiniMap = new Class({
	initialize: function(el, options){
		this._el = el;
		this._options = options;
		
		this._pois = new Array();
		
		this.initMap(this._options.center);
	},
	
	initMap: function( mode )
	{
		this._map = new google.maps.Map2( this._el );
		this._map.setMapType( G_SATELLITE_MAP );
		this._map.addControl( new google.maps.SmallZoomControl() );
		this._map.addControl( new google.maps.MenuMapTypeControl() );
		//if (this._options.modesOn)
		//	this._map.addControl( new google.maps.MapTypeControl() );
		switch (mode)
		{
			case 'area':
				var bounds = new google.maps.LatLngBounds( new google.maps.LatLng(this._options.sw.lat, this._options.sw.lng), new google.maps.LatLng(this._options.ne.lat, this._options.ne.lng) );
				var center = bounds.getCenter();
				var zoom = this._map.getBoundsZoomLevel( bounds );
			break;
			case 'point':
				var center = new google.maps.LatLng(this._options.lat, this._options.lng);
				var zoom = parseInt( this._options.zoom || 8 );
			break;
		}
		this._map.setCenter(center, zoom);
	},
	
	alert: function( content, autoclose )
	{
	},
	
	closeAlert: function( )
	{
	},
	
	addMarker: function( lat, lng )
	{
		var marker = new Point( new google.maps.LatLng(lat, lng), { 'type': 'general' } );
		this._map.addOverlay( marker );
	},
	
	addTrip: function( xml )
	{
		var id = getXMLdata( xml.getElementsByTagName('id')[0] );
		var style = xml.getAttribute('tripstyle');
		var trip = new Path( this, id, { 'style': style } );
		trip.loadFromXML(xml);
	},
	
	addPoi: function( params )
	{
		var poi = new Poi( this, params );
		this._pois[ this._pois.length ] = poi;
		this.bounds();
		return poi;
	},
	
	removePoi: function( poi )
	{
		poi.remove();
	},
	
	cleanPois: function( )
	{
		var pois = this._pois;
		for (i=0; i<pois.length; i++)
		{
			this.removePoi(pois[i]);
		}
	},
	
	bounds: function()
	{
		var lat = new Array([this._map.getCenter().lat()]);
		var lng = new Array([this._map.getCenter().lng()]);
		for (var i=0; i<this._pois.length; i++)
		{
			var poi = this._pois[i];
			lat[lat.length] = poi.getLatLng().lat();
			lng[lng.length] = poi.getLatLng().lng();
		}
		var bounds = new google.maps.LatLngBounds( new google.maps.LatLng(lat.max(), lng.min()), new google.maps.LatLng(lat.min(), lng.max()) );
		var center = bounds.getCenter();
		var zoom = this._map.getBoundsZoomLevel( bounds );
		this._map.setCenter(center, zoom);
	}
});

MiniMap.implement(new Events, new Options);

var Panel = new Class({
	Implements: [Events, Options],
	
	initialize: function( el, panel, options )
	{
		this._el = el;
		this.panel = panel;
		this._options = options;
		
		if (!this._el._panelsObj)
		{
			this._el._panelsObj = new Array();
			this._el._panelsPos = new Array();
		}
		
		this.create();
	},
	
	create: function()
	{
		var size = this._el.getSize();
		var position = this._el.getPosition();
		
		switch (this._options.position)
		{
			case 'left':
				this.panelWidth = 500;
			break;
			case 'right':
				this.panelWidth = 250;
			break;
		}
		this.closeWidth = 19;
		
		if (!this._el._panelsPos[ this._options.position ])
		{
			switch (this._options.position)
			{
				case 'left':
					var floatPos = 'left';
					var closePos = 'right';
					var scrollerWidth = this.closeWidth;
					this.offset = 0;
				break;
				case 'right':
					var floatPos = 'right';
					var closePos = 'left';
					var scrollerWidth = 'auto';
					this.offset = 18;
				break;
			}
			this._el._panelsPos[ this._options.position ] = {};
			this._el._panelsPos[ this._options.position ].float = new Element('div').setStyles({'float': floatPos, 'position': 'relative', 'z-index': 1000, 'width': 0 }).inject( this._el, 'before');
			this._el._panelsPos[ this._options.position ].side = new Element('div', {'class': 'poi-panel_side'}).setStyles({'position': 'relative', 'overflow': 'hidden', 'width': this.closeWidth, 'margin-left': -this.offset} ).inject( this._el._panelsPos[ this._options.position ].float, 'top' );
			this._el._panelsPos[ this._options.position ].scroller = new Element('div', {'class': 'poi-panel_scroller'}).setStyles({'overflow': 'hidden', 'width': scrollerWidth}).inject(this._el._panelsPos[ this._options.position ].side);
			this._el._panelsPos[ this._options.position ].closes = new Element('div').setStyles({'float': closePos, 'width': this.closeWidth, 'height': size.y } ).inject(this._el._panelsPos[ this._options.position ].scroller, 'top');
			this._el._panelsPos[ this._options.position ].container = new Element('div').setStyles({'display': 'none'}).inject( this._el._panelsPos[ this._options.position ].scroller );
			
			this._el._panelsPos[ this._options.position ].side.fx = new Fx.Morph( this._el._panelsPos[ this._options.position ].side ); // this.panelHeight - this.closeWidth
			this._el._panelsPos[ this._options.position ].scroller.fx = new Fx.Morph( this._el._panelsPos[ this._options.position ].scroller );
			this._el._panelsPos[ this._options.position ].opened = -1;
		}
		
		this.panel.closeLink = new Element('a', {'class': 'panel_close '+(this._options.closeCSS ? this._options.closeCSS : 'poi-panel_close'), 'href': 'javascript:;'}).set('html', '<span>&nbsp;</span>').addEvent('click', this.switchPanel.bind(this) ).inject(this._el._panelsPos[ this._options.position ].closes);
		this.panel.inject( this._el._panelsPos[ this._options.position ].container );
		this.panel.setStyles({'overflow': (this._options.overflow || 'auto'), 'height': size.y});
		
		this.selected = false;
		this.index = this._el._panelsObj.length;
		this._el._panelsObj[ this.index ] = this;
		
		//this.close();
		
		this.repos();
		
		//document.addEvent('startedmap', function() {
			var fn = this.repos.bind(this);
			this._el.map.addEvent('resizing', fn );
		//}.bind(this) );
		
		if (this._options.open == 'true')
			this.open();
		else
			this.panel.setStyle('display', 'none');
	},
	
	repos: function( )
	{
		var size = this._el.getSize();
		
		//this.map._panelsPos[ this._options.position ].side.setStyle('width', this.closeWidth);
		
		this.panel.closeLink.setStyle('height', size.y / 3 );
		this.panel.setStyle('height', size.y );
		this.fireEvent('resizing');
	},
	
	open: function( )
	{
		this.viewPanel();
		this._el._panelsPos[ this._options.position ].container.setStyle('display', 'block');
		switch (this._options.position)
		{
			case 'left':
				this._el._panelsPos[ this._options.position ].side.fx.start( { 'width': this.panelWidth - this.closeWidth } );
				this._el._panelsPos[ this._options.position ].scroller.fx.start( { 'width': this.panelWidth - this.closeWidth } ).chain( function() { this.choosePanel(); }.bind(this) );
			break;
			case 'right':
				this._el._panelsPos[ this._options.position ].side.fx.start( { 'width': this.panelWidth, 'margin-left': -this.panelWidth } ).chain( function() { this.choosePanel(); }.bind(this) );
			break;
		}
		this._el._panelsPos[ this._options.position ].opened = this.index;
		
		this._el.setStyle( 'margin-'+this._options.position, parseInt(this.panelWidth-40) / 2 );
		this._el.map.checkResize();
		
		this.fireEvent('open');
	},
	
	close: function( )
	{
		this.viewPanel();
		switch (this._options.position)
		{
			case 'left':
				this._el._panelsPos[ this._options.position ].side.fx.start( { 'width': this.closeWidth } ); 
				this._el._panelsPos[ this._options.position ].scroller.fx.start( { 'width': this.closeWidth } ).chain( function() { this.hidePanel(); }.bind(this) );
			break;
			case 'right':
				this._el._panelsPos[ this._options.position ].side.fx.start( { 'width': this.closeWidth, 'margin-left': -this.offset } ).chain( function() { this.hidePanel(); }.bind(this) );
			break;
		}
		
		this._el.setStyle( 'margin-'+this._options.position, 0 );
		this._el.map.checkResize();
		
		this.fireEvent('close');
	},
	
	hidePanel: function( )
	{
		this._el._panelsPos[ this._options.position ].container.setStyle('display', 'none'); 
		this._el._panelsPos[ this._options.position ].opened = -1;
		this.selected = false;
	},
	
	switchPanel: function( )
	{
		if (this._el._panelsPos[ this._options.position ].opened !== -1)
		{
			if (this.index === this._el._panelsPos[ this._options.position ].opened)
				this.close();
			else
			{
				this.viewPanel();
				this.choosePanel();
			}
		}
		else
		{
			this.open();
		}
	},
	
	viewPanel: function( )
	{
		for (var index = 0; index < this._el._panelsObj.length; index++)
		{
			if (this._options.position == this._el._panelsObj[index]._options.position)
			{
				if (index == this.index)
					this._el._panelsObj[index].panel.setStyle('display', 'block');
				else
					this._el._panelsObj[index].panel.setStyle('display', 'none');
			}
		}
	},
	
	choosePanel: function( )
	{
		for (var index = 0; index < this._el._panelsObj.length; index++)
		{
			if (this._options.position == this._el._panelsObj[index]._options.position)
			{
				if (index == this.index) // this._el._panelsPos[ this._options.position ].opened
				{
					//this._el._panelsObj[index].panel.setStyle('display', 'block');
					this._el._panelsObj[index].panel.closeLink.addClass('panel_close_selected');
					this._el._panelsObj[index].selected = true;
					this.fireEvent('focus');
				}
				else
				{
					//this._el._panelsObj[index].panel.setStyle('display', 'none');
					this._el._panelsObj[index].panel.closeLink.removeClass('panel_close_selected');
					this._el._panelsObj[index].selected = false;
					this._el._panelsObj[index].fireEvent('blur');
				}
			}
		}
		this._el._panelsPos[ this._options.position ].opened = this.index;
	}
});

var Complex = new Class({
	Implements: [Events, Options],
	
	queryString: function( )
	{
		var points = new Array();
		$each(this._markers, function(marker, i){
			points[points.length] = marker.getLatLng().lat() + ',' + marker.getLatLng().lng();
		}.bind(this) );
		return points.join("|", points);
	},
	
	decodePoints: function( string )
	{
		var pts = string.split(",");
		var points = new Array();
		for (var i=0; i<pts.length; i++)
		{
			var latlng = pts[i].split(" ");
			points[ i ] = new google.maps.LatLng( latlng[0], latlng[1] );
		}
		return points;
	},
	
	move: function(index, latlng)
	{
		this._markers[index].setLatLng( latlng );
		//this.fireEvent('marker-moved', [this._markers[index], this]);
	},
	
	remove: function( )
	{
		this.clean();
		this.fireEvent('remove');
	},
	
	clean: function( )
	{
		if (this._overlay)
		{
			this._map.removeOverlay( this._overlay );
		}
	},
	
	select: function( )
	{
		this._markers.each(function(marker){
			marker.select(true);
		}.bind(this) );
		this.fireEvent('select');
	},
	
	getMarker: function( index )
	{
		return this._markers[ index ];
	},
	
	launchRemove: function( )
	{
		var toRemove = new Array();
		var toSave = new Array();
		for (var i=0; i<this._markers.length; i++)
		{
			if (this._markers[i].selected)
				toRemove[toRemove.length] = this._markers[i];
			else
				toSave[toSave.length] = this._markers[i];
		}
		this._markers.length = 0;
		this._markers = toSave;
		
		if (this._markers.length == 0)
			this.remove();
		else
		{
			this.reIndex();
			this.build();
		}
		if (toRemove.length > 0)
			for (var j=0; j<toRemove.length; j++)
			{
				this.removeMarker(toRemove[j]);
			}
	},
	
	selectMarker: function( marker, multiple )
	{
		if (multiple == false)
		{
			$each(this._markers, function(stop, i){
				if ( (marker != stop) && (stop.selected) )
					stop.deselect();
			}.bind(this) );
		}
	},
	
	removeMarker: function( marker )
	{
		//this.fireEvent('marker-removed', [marker, this], 10 );
		marker.remove();
	},
	
	reIndex: function( )
	{
		for (i=0; i<this._markers.length; i++)
		{
			this._markers[i].setIndex( i );
			this._markers[i].setContent( i+1 );
		}
	},
	
	countMarkers: function( ) {
		return this._markers.length;
	},
	
	roundCoord: function(coord) {
		var r = 1000000;
		//return parseInt( coord *  r) / r;
		return coord;
	}
});


function initObjects()
{
	Point.prototype = new google.maps.Overlay();
	Point.prototype.initialize = function(map)
	{
		this.map_ = map;
	    this._img = new Element("span", {'class': 'marker marker-'+this._options.type} ).setStyles({'position': "absolute"});
		this._fx = new Fx.Tween(this._img, { 'property': 'opacity' }).set(0);
		this._img.addEvent('click', this.select.pass(false, this) );
		if (this._options.content)
			this._img.set('html', this._options.content);
		
		map.getPane(G_MAP_MARKER_PANE).appendChild(this._img);
		
		if (this._options.tip)
		{
			this._tip = new Element("span", {'class': 'marker-tip'}).set('html', '<span class="marker-tip-span">'+this.parseTip( this._options.tip )+'</span>').setStyles({'position': 'absolute', 'z-index': 1000});
			this._tip.fx = new Fx.Tween(this._tip, {'property': 'opacity', 'link': 'cancel'}).set(0);
			this._img.addEvents( {
				'mouseenter': function() {
					this.positionTip( );
					this._tip.fx.start(1);
				}.bind(this),
				'mouseleave': function() {
					if (this._tipfxTimer) $clear(this._tipfxTimer);
					this._tipfxTimer = this._tip.fx.start.delay(200, this._tip.fx, 0);
				}.bind(this)
			} );
			this._tip.addEvents( {
				'mouseenter': function() {
					if (this._tipfxTimer) $clear(this._tipfxTimer);
				}.bind(this),
				'mouseleave': function() {
					if (this._tipfxTimer) $clear(this._tipfxTimer);
					this._tipfxTimer = this._tip.fx.start.delay(200, this._tip.fx, 0);
				}.bind(this)
			} );
			//map.getPane(G_MAP_MARKER_PANE).appendChild(this._tip);
			document.body.appendChild(this._tip);
		}
		
		// options
		if (this._options.draggable == true)
			this.initDrag();
		
		// appear
		this._fx.start(1);
	}
	Point.prototype.remove = function()
	{
		this._img.dispose();
		if (this._tip)
			this._tip.dispose();
		this.fireEvent('remove');
	}
	Point.prototype.copy = function()
	{
		return new Point(this._point,  this._options);
	}
	Point.prototype.redraw = function(force)
	{
		this.positionTip( );
		if (!force) return;
		var size = this._img.getSize();
    	var c = this.map_.fromLatLngToDivPixel(this._point);
		this._img.setStyle('left', (c.x - (size.x/2)) + "px");
		this._img.setStyle('top', (c.y -  (size.y/2)) + "px");
	}
	Point.prototype.positionTip = function( )
	{
		if (this._tip)
		{
			var size = this._img.getSize();
			var position = this._img.getPosition();
			this._tip.fx.set(0);
			this._tip.setStyle('left', position.x + (size.x) );
			this._tip.setStyle('top', position.y - (size.y/2) );
			//this._tip.setStyle('left', (c.x + (size.x/2)) + "px");
			//this._tip.setStyle('top', (c.y -  (size.y/2)) + "px");
		}
	}
	
	/// ///
	Point.prototype.updateTip = function( tip )
	{
		this._tip.getElement('span').transition = 'none';
		this._tip.getElement('span').setContent(tip);
	}
	
	Point.prototype.parseTip = function( tip )
	{
		if ( (tip.indexOf('.jpg') !== -1) || (tip.indexOf('.JPG') !== -1) )
			return '<img src="'+tip+'" />';
		else
			return new Element('span').set('html', tip).get('text');
	}
	
	Point.prototype.initDrag = function()
	{
		this._drag = new Drag.Move( this._img );
		this._img.addEvent('mousedown', function(e) { new Event(e).stop(); } );
		this._drag.addEvent('onDrag', this.dragged.bind(this) );
		this._drag.addEvent('onComplete', this.dropped.bind(this) );
	}
	
	Point.prototype.getGeo = function()
	{
		if (this.revGeoXHR)
			this.revGeoXHR.cancel();
		this.revGeoXHR = new Request( {
			url: 'request.php',
			data: "task=reverse&lat=" + this._point.lat() + '&lng=' + this._point.lng(),
			autoCancel: true,
			method: "get"
		} ).send();
		this.revGeoXHR.addEvent('onSuccess', function( ) {
			var xml = this.revGeoXHR.response.xml;
			if (xml.getElementsByTagName('name').length > 0)
			{
				var name = getXMLdata( xml.getElementsByTagName('name')[0] );
				var country = xml.getElementsByTagName('country')[0].getAttribute('code');
				this.geo = name;
				this.country = country;
				this.fireEvent('geo', [this, name] );
			}
		}.bind(this) );
	}
	
	Point.prototype.getIndex = function()
	{
		return this._options.index;
	}
	
	Point.prototype.getLatLng = function()
	{
		return this._point;
	}
	
	Point.prototype.setIndex = function( index )
	{
		this._options.index = index;
	}
	
	Point.prototype.setLatLng = function(latlng)
	{
		if (latlng != this._point)
		{
			this._point = latlng;
			this.redraw(true);
			this.fireEvent('move');
		}
	}
	
	Point.prototype.setAddress = function( search )
	{
		if (!this.geocoder)
			this.geocoder = new google.maps.ClientGeocoder();
		this.geocoder.getLocations(search, this.parseMoveBySearch.bind(this) );
	}
	
	Point.prototype.parseMoveBySearch = function( response )
	{
		if (!response || response.Status.code != 200) {
			this.fireEvent('error', 'Spiacenti, non siamo riusciti a trovare il posto indicato');
		} else {
			place = response.Placemark[0];
			point = new google.maps.LatLng(place.Point.coordinates[1], place.Point.coordinates[0]);
			this.blockGeo = true;
			this.setLatLng( point );
		}
	}
	
	Point.prototype.setContent = function( content )
	{
		if (this._options.empty != true)
			this._img.set('html', content);
	}
	/// xtra ///
	Point.prototype.dropped = function( )
	{
		var latlng = this.mouseToLatLng();
		this.blockGeo = false;
		this.setLatLng( latlng );
	}
	
	Point.prototype.dragged = function( )
	{
		//var latlng = this.mouseToLatLng();
		//this.setLatLng( latlng );
		//document.title = this.mouseToLatLng();
		this.fireEvent('drag');
	}
	
	Point.prototype.select = function( multiple )
	{
		this.selected = true;
		this._img.addClass('marker-selected');
		this.fireEvent('select', [this, multiple] );
	}
	
	Point.prototype.deselect = function( multiple )
	{
		this.selected = false;
		this._img.removeClass('marker-selected');
		this.fireEvent('deselect', [this, multiple] );
	}
	
	/// utilities ///
	Point.prototype.addEvent = function( type, fn )
	{
		if (fn != $empty){
			this.$events = this.$events || {};
			this.$events[type] = this.$events[type] || [];
			this.$events[type].include(fn);
		}
		return this;
	}
	
	Point.prototype.fireEvent = function(type, args, delay)
	{
		if (!this.$events || !this.$events[type]) return this;
		this.$events[type].each(function(fn){
			fn.create({'bind': this, 'delay': delay, 'arguments': args})();
		}, this);
		return this;
	}
	
	Point.prototype.mouseToLatLng = function( )
	{
		var mouse = this._drag.mouse.now;
		var mapPosition = $(this.map_.getPane(G_MAP_MARKER_MOUSE_TARGET_PANE)).getPosition();
		var point = new google.maps.Point(mouse.x - mapPosition.x, mouse.y - mapPosition.y);
		var latlng = this.map_.fromDivPixelToLatLng( point );
		return latlng;
	}
}

function Point(point, options)
{
	this.selected = false;
	this._point = point;
	this._options = options;
}
