document.addEvent('domready', function() {
	if ($('trip-stops-toggler'))
		s.initTripStopsToggler($('trip-stops-toggler'));
	if ($('trip-embed_input'))
		s.initEmbed( $('trip-embed_input') );
} );

document.addEvent('startedmap', function() {
	if ($('map'))
		s.initMapPanel( $('map') );
	
	s.initTrip( s.body );
	
	document.addEvent('updateblock', function(obj) {
		s.initTrip( obj );
	} );
} );

siteEngine.prototype.initTrip = 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('trip-stop'))		this.tripBlock(objs[i]);
		if (objs[i].hasClass('stop'))			this.stopTrip(objs[i]);
		if (objs[i].hasClass('add-stop'))		this.newStopTrip(objs[i]);
		if (objs[i].hasClass('move-here'))		this.moveHere(objs[i]);
		if (objs[i].hasClass('save-first'))		this.saveFirst(objs[i]);
		
		if (objs[i].hasClass('loop'))			this.loopTrips(objs[i]);
		if (objs[i].hasClass('putonmap'))		this.putOnMapTrip(objs[i]);
		
		if (objs[i].hasClass('mini-tripmap'))	this.miniTripMap(objs[i]);
	}
}

siteEngine.prototype.initTripStopsToggler = function( obj )
{
	obj.opened = false;
	obj.addEvent('click', function(obj) {
		if (obj.opened) { obj.set('html', 'Espandi le tappe'); obj.removeClass('selected'); obj.opened = false; }
		else			{ obj.set('html', 'Comprimi le tappe'); obj.addClass('selected'); obj.opened = true; }
		$('trip-stops').getElements('.expand-toggler').fireEvent('click');
	}.pass(obj, this) );
}

siteEngine.prototype.initEmbed = function( obj )
{
	obj.addEvent('click', function(obj) {
		obj.select();
	}.pass(obj, this) );
}

siteEngine.prototype.initMapPanel = function( obj )
{
	obj.importProps();
	
	if (obj.panel)
	{
		obj.map.panel = new TripPanel( obj.map, obj.panel, {
			'loadPanel': obj.loadPanel,
			'loadMarker': obj.loadMarker,
			'idTrip': obj.idTrip,
			'tabs': obj.tabs,
			'loadTabs': obj.loadTabs,
			'logged': obj.logged,
			'panelForm': obj.panelForm,
			'panelContent': obj.panelContent,
			'orderProto': obj.orderProto
		} );
		obj.map.addEvent('marker-added', obj.map.panel.addStopTrip.bind(obj.map.panel) );
		obj.map.addEvent('marker-moved', obj.map.panel.movedMarker.bind(obj.map.panel) );
		obj.map.addEvent('marker-removed', obj.map.panel.removeMarker.bind(obj.map.panel) );
		obj.map.addEvent('marker-selected', obj.map.panel.selectStopTrip.bind(obj.map.panel) );
		obj.map.addEvent('marker-geo', obj.map.panel.geoStopTrip.bind(obj.map.panel) );
		
		obj.map.addEvent('trip-added', obj.map.panel.addedTrip.bind(obj.map.panel) );
		obj.map.addEvent('trip-removed', function(trip) { if (trip._id == 'new') this.reset(); }.bind(obj.map.panel) );
		obj.map.addEvent('trip-modified', function(trip) { if (trip._id == 'new') this.setup(); }.bind(obj.map.panel) );
		
		if (obj.formUpdate)
		{
			obj.map.panel.addEvent('added', function( obj ) {
				this.addUpdate( $(obj.formUpdate) );
			}.pass(obj, this) );
		}
	}
}

siteEngine.prototype.tripBlock = function( obj )
{
	obj.targetMap = $(obj.targetEl);
	obj.input = obj.getElement('.local');
	obj.latInput = obj.getElement('.lat');
	obj.lngInput = obj.getElement('.lng');
	obj.distanceInput = obj.getElement('.distance');
	obj.summaryInput = obj.getElement('.summary');
	obj.find = obj.getElement('.find');
	obj.orders = obj.getElements('.orderlink');
	obj.insertStop = obj.getElement('.insertstop');
	obj.toremove = obj.getElement('.remove');
	obj.tripremove = obj.getElement('.removeTrip');
	obj.gopoi = obj.getElement('.gopoi');
	obj.pushpin = obj.getElement('.drag');
	obj.minimap = obj.getElement('.mini-map');
	
	if (obj.pushpin)
		this.applyDrag( obj );
	if (obj.drawStop == 'true')
		this.stopTrip( obj );
	if (obj.input)
		this.stopInput( obj );
	if (obj.distanceInput)
		this.distanceInput( obj );
	if (obj.summaryInput)
		this.summaryInput( obj );
	if (obj.orders.length > 0)
		this.orderTrip( obj );
	if (obj.insertStop)
		this.insertStop( obj );
	if (obj.toremove)
		this.stopToRemove( obj );
	if (obj.tripremove)
		this.tripToRemove( obj );
	if (obj.gopoi)
		this.goPoi(obj);
	if (obj.minimap)
		this.miniMap(obj);
	
	//////////// LINKing //////////////////
	if (obj.index)
	{
		switch (obj.mode)
		{
			case 'trip':
				obj.trip = obj.targetMap.map.findTrip( obj.tid );
				var marker = obj.trip.getMarker(obj.index);
				if (obj.input) marker.geo = obj.input.get('value');
				if (obj.refresh)
				{
					marker.addEvent('move', function(obj, marker) {
						this.refreshTripStop(obj, marker);
					}.pass([obj, marker], this) );
				}
			break;
			case 'zone':
				obj.zone = obj.targetMap.map.findZone( obj.zid );
				var marker = obj.zone.getMarker(obj.index);
			break;
		}
		if (marker)
		{
			marker.feed = obj;
			obj.marker = marker;
			obj.marker.addEvent('error', function(error) { obj.targetMap.map.alert( error, 1 ); } );
			obj.fireEvent('marker-linked');
		}
	}
}
	
siteEngine.prototype.applyDrag = function( obj )
{
	obj.dd = new DragDrop( obj.pushpin, obj.targetMap );
	obj.dd.addEvent('start', function( obj ) {
		obj.targetMap.map.movingPutMap = true;
	}.pass(obj, this) );
	obj.dd.addEvent('drop', function( obj ) {
		obj.targetMap.map.puttedPutMap(obj.dd.getMouse(), { 'mode': obj.mode, 'action': obj.action, 'tid': obj.tid, 'index': obj.index } );
	}.pass(obj, this) );
}

siteEngine.prototype.newStopTrip = function( obj )
{
	obj.addEvent('click', function(obj) {
		var map = $(obj.targetEl).map;
		var point = map.getCenter();
		var trip = map.findTrip( 'new' );
		if (!trip)
			trip = map.addTrip('new', { 'style': 'new', 'editable': 'true' } );
		trip.add( { 'point': point, 'noautogeo': (obj.noautogeo == 'true') } );
		trip.build();
	}.pass(obj, this) );
}

siteEngine.prototype.moveHere = function( obj )
{
	var map = $(obj.targetEl).map;
	var trip = map.findTrip( 'new' );
	var marker = trip.getMarker(obj.index)
	marker.setLatLng( new google.maps.LatLng( obj.lat, obj.lng ) );
}

siteEngine.prototype.insertStop = function( obj )
{
	obj.insertStop.addEvent('click', function(obj) {
		var map = $(obj.targetEl).map;
		var point = obj.marker.getLatLng();
		var trip = map.findTrip( obj.tid );
		obj.targetMap.map.panel.addEvent('added', function(page) {
			page.getElement('.local').set('value', this.getElement('.local').get('value') );
			page.inject( this, 'after' );
			this.targetMap.map.panel.resetTrip( this.tid );
		}.bind(obj) );
		trip.add( { 'point': point, 'noGeo': true } );
		
		/*var clone = obj.clone();
		clone.tid = obj.tid; clone.lat = obj.lat; clone.lng = obj.lng; clone.targetMap = obj.targetMap;
		
		obj.targetMap.map.panel.resetTrip( obj.tid );*/
	}.pass(obj, this) );
}

siteEngine.prototype.refreshTripStop = function( obj, marker )
{
	var ref = obj.refresh.split(',');
	//var coord = 'lat=' + marker.getLatLng().lat() + '&lng=' + marker.getLatLng().lng();
	for (var i=0; i<ref.length; i++)
	{
		var refresh = $(ref[i]);
		refresh.fireEvent('preload');
		var url = refresh.getURL();
		//url += ( (url.indexOf('?') !== -1) ? '&' : '?' ) + coord;
		this.addMouseTip( 'Caricamento...', 0 );
		obj.rfsxhr = new Request( {'url': url} ).send();
		obj.rfsxhr.addEvent('onComplete', function(obj, refresh) {
			var response = obj.rfsxhr.response.text;
			refresh.setContent( response );
			this.closeMouseTip( );
		}.pass([obj,refresh], this) );
	}
}

siteEngine.prototype.stopTrip = function( obj )
{
	var point = new google.maps.LatLng( obj.lat, obj.lng );
	var map = obj.targetMap.map;
	var trip = map.findTrip( obj.tid );
	var params = { 'point': point }
	if (!trip)
	{
		trip = map.addTrip(obj.tid, { 'style': 'new', 'editable': ( obj.editable || true ) } );
	}
	if (obj.icon)
		params.icon = obj.icon;
	trip.add( params );
	if (obj.drawTrip)
	{
		trip.build();
	}
}

siteEngine.prototype.tripToRemove = function( obj )
{
	obj.tripremove.addEvent('click', function(obj) {
		if (!obj.tripremove.continueClick()) return false;
		obj.targetMap.map.cleanTrips();
		obj.trip = obj.targetMap.map.findTrip( obj.tid );
		if (obj.trip)
		{
			obj.targetMap.map.cleanTrip(obj.trip);
		}
	}.pass(obj, this) );
	obj.tripremove.addEvent('click', function(e) {
		new Event(e).stop();
	});
}

siteEngine.prototype.stopInput = function( obj )
{
	obj.startSearch = obj.input.get('value');
	obj.input.addEvent('keyup', function() {
		if (obj.find)
			obj.find.disabled = ( (obj.input.get('value') == obj.startSearch) ? true : false);
	} );
	if (obj.find)
	{
		obj.find.addEvent('click', function() {
			obj.marker.setAddress( obj.input.get('value') );
			return false;
		} );
	}
}

siteEngine.prototype.distanceInput = function( obj )
{
	if (obj.trip)
		obj.distanceInput.set('value', obj.trip.getDistance( obj.index ) );
}

siteEngine.prototype.summaryInput = function( obj )
{
	if (obj.trip)
		obj.summaryInput.set('value', obj.trip.getSummary( obj.index ) );
}

siteEngine.prototype.orderTrip = function( obj )
{
	for (var i=0; i<obj.orders.length; i++)
	{
		obj.orders[i].addEvent('click', function(obj, button) {
			var prev = obj.getPrevious('.map-stop');
			var next = obj.getNext('.map-stop');
			var changed = false;
			if (button.hasClass('move-up') && prev)
			{
				obj.inject( prev, 'before' );
				changed = true;
			} 
			if (button.hasClass('move-down') && next)
			{
				obj.inject( next, 'after' );
				changed = true;
			}
			
			if (changed)
			{
				obj.targetMap.map.panel.resetTrip( obj.tid );
			}
		}.pass([obj, obj.orders[i]], this) );
	}
}

siteEngine.prototype.goPoi = function( obj )
{
	obj.gopoi.addEvent('click', function(obj) {
		var target = $(obj.gopoi.targetEl);
		target.getElement('.country').set('value', obj.marker.country);
		target.getElement('.search').set('value', obj.marker.geo);
		target.getElement('.lat').set('value', obj.marker.getLatLng().lat());
		target.getElement('.lng').set('value', obj.marker.getLatLng().lng());
		target.getElement('.scope').set('value', obj.gopoi.scope);
		target.fireEvent('submit');
		this.sidebar.opened = true;
	}.pass(obj, this) );
	obj.gopoi.addEvent('click', function(e) { new Event(e).stop(); } );
}

siteEngine.prototype.stopToRemove = function( obj )
{
	obj.toremove.addEvent('click', function(obj) {
		if (!obj.toremove.continueClick()) return false;
		obj.marker.selected = true;
		obj.trip.selectMarker( obj.marker, false );
		obj.trip.launchRemove();
	}.pass(obj, this) );
	obj.toremove.addEvent('click', function(e) {
		new Event(e).stop();
	});
}

siteEngine.prototype.loopTrips = function( obj )
{
	obj.targetMap = $(obj.targetEl);
	obj.loopIndex = 0;
	obj.items = obj.getElements( '.' + obj.childrens );
	if (obj.items.length > 0)
	{
		obj.targetMap.map.addEvent('trip-loaded', function(obj) {
			obj.targetMap.map.addLoop( this.viewTrip.delay( (obj.delay || 10000), this, obj), 'trip-loop' );
		}.pass(obj, this) );
		this.viewTrip( obj );
	}
}

siteEngine.prototype.putOnMapTrip = function( obj )
{
	obj.map = $(obj.targetEl).map;
	obj.items = obj.getElements( '.' + obj.childrens );
	if (obj.items.length > 0)
	{
		obj.map.loadTrip( obj.items[0].tid );
	}
}

siteEngine.prototype.viewTrip = function( obj )
{
	if (obj.prev)
		obj.prev.removeClass('trip-selected');
	
	var item = obj.items[ obj.loopIndex ];
	item.addClass('trip-selected');
	obj.targetMap.map.loadTrip( item.tid );
	obj.loopIndex = ( (obj.loopIndex == (obj.items.length-1)) ? 0 : obj.loopIndex+1 );
	obj.prev = item;
}

siteEngine.prototype.miniMap = function( obj )
{
	var options = {
		'center': 'point',
		'lat': obj.lat,
		'lng': obj.lng,
		'zoom': 15
	};
	obj.minimap.map = new MiniMap( obj.minimap, options );
	obj.minimap.map.addMarker(obj.lat, obj.lng);
}

siteEngine.prototype.miniTripMap = function( obj )
{
	var options = {
		'center': obj.center,
		'sw': { 'lat': obj.sw_lat, 'lng': obj.sw_lng },
		'ne': { 'lat': obj.ne_lat, 'lng': obj.ne_lng },
		'modesOn': true
 	};
	var xml = docFromXML(obj.getElement('textarea').get('value'));
	obj.map = new MiniMap( obj, options );
	obj.map.addTrip( xml );
}

siteEngine.prototype.saveFirst = function( obj )
{
	obj.addEvent('click', function(obj) {
		obj.form = $(obj.targetEl);
		obj.form.targetEl = 'redirect';
		obj.form.redirect = obj.get('href');
		obj.form.fireEvent('submit');
		return false;
	}.pass(obj, this) );
}
	

var TripPanel = new Class({
	Implements: [Events],
	
	initialize: function(map, el, options) {
		this._map = map;
		this._el = el;
		this._options = options;
		
		this.addPanelXHR = new Array;
		
		if (this._el == 'sidebar')
			this.create();
		else
			this.panel = $(this._el);
	},
	
	load: function( params )
	{
		//if (this.panel == true)
		//{
			var params = $merge(params, { 'load':'module', 'name': this._options.loadPanel } );
			this.panelXHR = new Request( {
				url: 'ajax.php',
				data: params,
				method: "post"
			} ).send();
			this.panelXHR.addEvent('onSuccess', function(data) {
				this.open(data);
			}.bind(this) );
		//}
	},
	
	control: function( )
	{
		var divs = this.panel.getElements('.map-stop');
		var nostops = this.panel.getElement('.no-stops');
		if (nostops)
			if (divs.length == 0)
				nostops.removeClass('ghost');
			else
				nostops.addClass('ghost');
	},
	
	addedTrip: function( map, trip )
	{
		trip.addEvent('changed', function(trip) {
			for (var i=0; i<trip._markers.length; i++)
			{
				var div = this.getDiv(i);
				if (div)
				{
					var distanceInput	= div.getElement('.distance');
					if (distanceInput)	distanceInput.set('value', trip.getDistance(i) );
					var summaryInput	= div.getElement('.summary');
					if (summaryInput)	summaryInput.set('value', trip.getSummary(i) );
				}
			}
		}.pass(trip, this) );
	},
	
	addStopTrip: function( stop, trip )
	{
		if ( !this.getDiv( stop.getIndex() ) )
		{
			this.panel.loading(1);
			var lastIndex = this.addPanelXHR.length;
			var page = new Element('div').inject(this.panel);
			var params = { 'mode': 'trip', 'name': this._options.loadMarker, 'load': 'module', 'action': 'add-stop', 'id_trip': this._options.idTrip, 'index': stop.getIndex(), 'lat': stop.getLatLng().lat(), 'lng': stop.getLatLng().lng() };
			this.addPanelXHR[ lastIndex ] = new Request( {
				url: 'ajax.php',
				data: params,
				method: "post"
			} ).send();
			this.addPanelXHR[ lastIndex ].addEvent('onSuccess', function(page, stop, trip, addindex) { this.panel.loading(0); this.add(page, stop, trip, addindex); }.pass([page, stop, trip, lastIndex ], this) );
		}
	},
	
	add: function( page, marker, complex, addindex )
	{
		var xhr = this.addPanelXHR[ addindex ];
		var content = xhr.response.text;
		if (content)
		{
			page.set('html', content);
			this.attachFx(page);
			document.fireEvent('updateblock', page);
			page.fx.start(1).chain( function(page) {
				page.getElement('div').inject( page.getPrevious('div'), 'after');
				page.dispose();
			}.pass(page,this) );
			if (this.mPanel)
			{
				this.mPanel.open( );
				//this.mPanel.choosePanel();
			}
			page.geoInput = page.getElement('.geo');
			if ( (page.geoInput) && (marker._options.noautogeo != true) )
				marker.getGeo();
			page.distanceInput = page.getElement('.distance');
				page.distanceInput.set('value', complex.getDistance(marker.getIndex()) )
			this.fireEvent('added', page).fireEvent('change', page);
		}
		this.control();
	},
	
	movedMarker: function( marker, complex )
	{
		var div = this.getDiv( marker.getIndex() );
		div.latInput = div.getElement('.lat');
		div.lngInput = div.getElement('.lng');
		div.geoInput = div.getElement('.geo');
		if (div.latInput && marker._point)
		{
			div.lat = marker.getLatLng().lat();
			div.lng = marker.getLatLng().lng();
			div.latInput.set('value', div.lat );
			div.lngInput.set('value', div.lng );
		}
		if (div.geoInput && marker.blockGeo != true)
			marker.getGeo();
	},
	
	geoStopTrip: function( stop, trip )
	{
		var div = this.getDiv( stop.getIndex() );
		div.geoInputs = div.getElements('.geo');
		if (div.geoInputs && stop.geo)
		{
			for (var i=0; i<div.geoInputs.length; i++)
			{
				var tag = div.geoInputs[i].get('tag');
				div.geoInputs[i].set( ( ( (tag == 'input') || (tag == 'textarea') ) ? 'value' : 'html'), stop.geo);
				div.geoInputs[i].fireEvent('change');
			}
		}
	},
	
	removeMarker: function( marker, complex )
	{
		var div = this.getDiv( marker.getIndex() );
		this.attachFx(div);
		div.fx.addEvent('onComplete', function(div) { this.remove(div); }.pass(div, this) );
		div.fx.start(0);
	},
	
	remove: function( div )
	{
		div.setStyle('display', 'none');
		div.removed = div.getElement('.removed');
		//div.remove();
		var toSave = new Array();
		if (div.removed)
		{
			// delete from logics
			div.set('class', '' );
			var blocks = div.getElements('.trip-stop');
			for (var i=0; i<blocks.length; i++)	blocks[i].set('class', '');
			//
			div.removed.set('value', '1');
			div.removed.fireEvent('change');
			div.deleted = true;
		}
		this.setup();
		this.fireEvent('removed', div).fireEvent('change', div);
		
		this.control();
	},
	
	reset: function( )
	{
		var divs = this.panel.getElements('.map-stop');
		for (var i=0; i<divs.length; i++)
		{
			if (divs[i].deleted != true)
			{
				this.remove( divs[i] );
			}
		}
	},
	
	resetTrip: function( tid )
	{
		this.setup();
				
		var trip = this._map.findTrip( tid );
		for (var i=0; i<trip._markers.length; i++)
			trip._markers[i]._img.dispose();
		trip._markers.length = 0;
		trip.clean();
		
		var stops = this.panel.getElements('.map-stop');
		for (var i=0; i<stops.length; i++)
		{
			s.stopTrip( stops[i] );
			var marker = trip.getMarker(stops[i].index);
			marker.feed = stops[i];
			stops[i].marker = marker;
		}
		
		this.control();
	},
	
	setup: function( )
	{
		var index = 0;
		var divs = this.panel.getElements('.map-stop');
		var last;
		for (var i=0; i<divs.length; i++)
		{
			//divs[i].block = divs[i].getElement('.trip-stop');
			divs[i]._index = divs[i].getElement('.index');
			divs[i]._ordering = divs[i].getElement('.ordering');
			divs[i]._distance = divs[i].getElement('.distance-stop');
			if (divs[i].deleted != true)
			{
				divs[i].index = index;
				divs[i].drawTrip = false;
				
				if (divs[i]._index)
					divs[i]._index.set('html', index+1);
				if (divs[i]._ordering)
					divs[i]._ordering.set('value', index);
				if (divs[i]._distance)
					divs[i]._distance.set('html', ( (index == 0) ? 'Partenza<input type="hidden" name="distanceStop['+divs[i].id_stop+']" value="0" class="distance" />' : 'km <input type="text" name="distanceStop['+divs[i].id_stop+']" value="" class="distance" readonly="readonly" />') );
					
				index++;
				last = i;
			}
		}
		// last one has drawTrip = true
		if (last)
			divs[last].drawTrip = true;
	},
	
	selectStopTrip: function( stop )
	{
		if (this.panel.hasClass('accordion'))
		{
			this.panel.accordion.display( stop.getIndex() );
		}
	},
	
	saveNewOrder: function( )
	{
		var orderings = new Array();
		var divs = this.panel.getElements('.id');
		for (var i=0; i<divs.length; i++)
		{
			orderings[i] = (divs[i].get('value') + ':' + i);
		}
		if (this.orderingXhr)
			this.orderingXhr.cancel();
		this.orderingXhr = new Request( {
			'url': this._options.orderProto,
			'data': 'ordering=' + orderings.join(','),
			'method': "post"
		} ).send();
		this.orderingXhr.addEvent('onComplete', function() {
			this.panel.setContent(this.orderingXhr.response.text);
		}.bind(this) );
		
	},
	
	loading: function( mode )
	{
		if (!this.loadingDiv)
		{
			this.loadingDiv = new Element('div', {'class': 'loading-trip-panel'}).setStyles({'position':'absolute'}).set('html', '&nbsp;').inject( this.panel, 'top' );
			this.loadingFx = new Fx.Tween(this.loadingDiv, {'link': 'chain', 'property': 'opacity'}).set(0);
		}
		var size = this.panel.getSize();
		this.loadingDiv.setStyles( { 'width': size.x, 'height': size.y } );
		switch (mode)
		{
			case 1: this.loadingFx.start(.7); break;
			case 0: this.loadingFx.start(0); break;
		}
	},
	
	/*** PANEL ***/
	create: function( )
	{
		var fn = this.repos.bind(this);
		this._map.addEvent('resizing', fn );
		
		this.form = $(this._options.panelForm);
		this.panel = $(this._options.panelContent);
		this.mPanel = m.addPanel( $('trip-panel'), { 'position': 'right', 'closeCSS': 'trip-panel_close' } );
		
		this.repos();
	},
	
	repos: function( )
	{
		var size = this._map._el.getSize();
		this.panel.setStyle('height',  size.y - 37 - 32 );
	},
	
	
	attachFx: function( div )
	{
		if (!div.fx)
			div.fx = new Fx.Tween( div, {'property': 'opacity'} ).set(0);
		//div.fx = new Fx.Tween( div, 'opacity').set( 0 ).start( 1 );
	},
	
	getDiv: function( index )
	{
		var ind = 0;
		var divs = this.panel.getElements('.map-stop');
		for (var i=0; i<divs.length; i++)
		{
			if (divs[i].deleted != true)
			{
				if (index == ind)
					return divs[i];
				ind++;
			}
		}
		return null;
	},
	
	module: function( obj )
	{
		var inputs = obj.getElements('input,select,textarea')
		for (var i=0; i<inputs.length; i++)
		{
			var func = function(obj)
			{
				if (this.updateTimer)
					$clear( this.updateTimer );
				this.updateTimer = this.save.delay(this.formDelay, this);
				//return false;
			}.bind(this);
			inputs[i].addEvent('change', func);
			inputs[i].addEvent('keypress', func);
		}
	},
	
	save: function( )
	{
		if (this.saveXHR)
			this.saveXHR.cancel();
		var params = this.form.toQueryString();
		this.saveXHR = new Request( {
			url: 'request.php?task=update_trip',
			data: params,
			autoCancel: true,
			method: "post"
		} ).send();
		//this.saveXHR.addEvent('onComplete', this.parse.bind(this) );
	}
} );



var PolylineEncoder = new Class( {
	encode: function(points)
	{
		var i = 0;
		var plat = 0;
		var plng = 0;
		var encoded_points = "";
		var encoded_levels = "";
		for(i = 0; i < points.length; ++i)
		{
			var point = points[i];
			var lat = point.lat();
			var lng = point.lng();
			var level = 1;
			var late5 = Math.floor(lat * 1e5);
			var lnge5 = Math.floor(lng * 1e5);
	
			dlat = late5 - plat;
			dlng = lnge5 - plng;
			
			plat = late5;
			plng = lnge5;
			
			encoded_points += this.encodeSignedNumber(dlat) + this.encodeSignedNumber(dlng);
			encoded_levels += this.encodeNumber(level);
		}
		
		return {
		  	encodedPoints: encoded_points,
		  	encodedLevels: encoded_levels
		}
	},
	
	// Encode a signed number in the encode format.
	encodeSignedNumber: function(num)
	{
		var sgn_num = num << 1;
		if (num < 0) {
			sgn_num = ~(sgn_num);
		}
		return(this.encodeNumber(sgn_num));
	},

	// Encode an unsigned number in the encode format.
	encodeNumber: function(num)
	{
		var encodeString = "";
		while (num >= 0x20) {
			encodeString += (String.fromCharCode((0x20 | (num & 0x1f)) + 63));
			num >>= 5;
		}
		encodeString += (String.fromCharCode(num + 63));
		return encodeString;
	},
	
	// Decode an encoded polyline into a list of lat/lng tuples.
	decodeLine: function(encoded)
	{
		var len = encoded.length;
		var index = 0;
		var array = [];
		var lat = 0;
		var lng = 0;
		
		while (index < len) {
			var b;
			var shift = 0;
			var result = 0;
			do {
				b = encoded.charCodeAt(index++) - 63;
				result |= (b & 0x1f) << shift;
				shift += 5;
			} while (b >= 0x20);
			var dlat = ((result & 1) ? ~(result >> 1) : (result >> 1));
			lat += dlat;

			shift = 0;
			result = 0;
			do {
				b = encoded.charCodeAt(index++) - 63;
				result |= (b & 0x1f) << shift;
				shift += 5;
			} while (b >= 0x20);
			var dlng = ((result & 1) ? ~(result >> 1) : (result >> 1));
			lng += dlng;
			//array.push([lat * 1e-5, lng * 1e-5]);
			array.push( new google.maps.LatLng(lat * 1e-5, lng * 1e-5) );
		}
		return array;
	},

	// Decode an encoded levels string into a list of levels.
	decodeLevels: function(encoded)
	{
		var levels = [];

		for (var pointIndex = 0; pointIndex < encoded.length; ++pointIndex) {
    		var pointLevel = encoded.charCodeAt(pointIndex) - 63;
			levels.push(pointLevel);
		}
		return levels;
	},

	// Decode the supplied encoded polyline and levels.
	decode: function(encoded_points, encoded_levels) {
		if (encoded_points.length==0 || encoded_levels.length==0) {
			return;
		}

		var enc_points = this.decodeLine(encoded_points);
		var enc_levels = this.decodeLevels(encoded_levels);
		
		if (enc_points.length==0 || enc_levels.length==0) {
			return;
		}

		/*if (enc_points.length != enc_levels.length) {
			return;
		}*/
		
		return {
			'points': enc_points,
			'levels': enc_levels
		}
	}
} );

var Path = new Class({
	Extends: Complex,
	
	initialize: function(map, id, options){
		this.main = map;
		this._map = map._map;
		this._id = id;
		this._options = options;
		this._style = options.style;
		this._points = new Array();
		this._markers = new Array();
		this._waypoints = new Array();
		
		this._overlays = new Array(); // for errors streight polylines
		
		/// configs
		this._trigger = '[points...levels]';
		this._styles = new Array();
		this._styles["new"] = { "color": "#cc0000", "weight": 2, "opacity": .8 };
		this._styles["temp"] = { "color": "#000000", "weight": 1, "opacity": .7 };
		this._styles['loaded'] = { "color": "#54A952", "weight": 3, "opacity": 1 };
		this._styles['loaded_0'] = { "color": "#0EDD00", "weight": 3, "opacity": 1 };
		this._styles['loaded_1'] = { "color": "#DD0005", "weight": 3, "opacity": 1 };
		this._styles['loaded_2'] = { "color": "#0011DD", "weight": 3, "opacity": 1 };
		this._styles['loaded_3'] = { "color": "#DD8F00", "weight": 3, "opacity": 1 };
		this._styles['loaded_4'] = { "color": "#DD00C7", "weight": 3, "opacity": 1 };
		
		this._dir = new google.maps.Directions(null, $('summary') );
		new google.maps.Event.addListener(this._dir, "load", this.parseDirection.bind(this) );
		new google.maps.Event.addListener(this._dir, "error", this.errorsDirections.pass(this._dir, this) );
		
		///
		this.dragDirIcon = new google.maps.Icon();
		this.dragDirIcon.image = "templates/map/drag_dir.png";
		this.dragDirIcon.iconSize=new GSize(8,8);
		this.dragDirIcon.iconAnchor=new GPoint(4,4);
		this.dragDirIcon.infoWindowAnchor=new GPoint(4,0);
		this.dragIcon = new google.maps.Marker(new google.maps.LatLng(0,0), {icon: this.dragDirIcon, draggable:true, "dragCrossMove": false, "bouncy":false} );
		new google.maps.Event.addListener(this.dragIcon, "dragstart", function() {
			this.startDragPath();
		}.bind(this) );
		new google.maps.Event.addListener(this.dragIcon, "dragend", function() {
			this.endDragPath();
		}.bind(this) );
		new google.maps.Event.addListener(this.dragIcon, "drag", function() {
			if (this.dragTimer)	$clear(this.dragTimer);
			this.dragTimer = this.dragPath.delay(300, this);
		}.bind(this) );
		
		this._map.addOverlay( this.dragIcon );
		this.dragIcon.hide();
	},
	
	loadFromXML: function( xml )
	{
		this.link 			= getXMLdata( xml.getElementsByTagName('link')[0] );
		this.name 			= getXMLdata( xml.getElementsByTagName('name')[0] );
		this.description 	= getXMLdata( xml.getElementsByTagName('description')[0] );
		this.distance 		= getXMLdata( xml.getElementsByTagName('distance')[0] );
		this.path 			= xml.getElementsByTagName('path')[0].nodeValue || xml.getElementsByTagName('path')[0].firstChild.data;
		if (xml.getElementsByTagName('bounds').length > 0)
		{
			this.sw = new google.maps.LatLng( getXMLdata( xml.getElementsByTagName('sw')[0].getElementsByTagName('lat')[0] ), getXMLdata( xml.getElementsByTagName('sw')[0].getElementsByTagName('lng')[0] ) );
			this.ne = new google.maps.LatLng( getXMLdata( xml.getElementsByTagName('ne')[0].getElementsByTagName('lat')[0] ), getXMLdata( xml.getElementsByTagName('ne')[0].getElementsByTagName('lng')[0] ) );
		}
		var stops = xml.getElementsByTagName('stop');
		for (var i=0; i<stops.length; i++)
		{
			var marker = new Point( new google.maps.LatLng( getXMLdata( stops[i].getElementsByTagName('lat')[0] ), getXMLdata( stops[i].getElementsByTagName('lng')[0] ) ), { 'type': stops[i].getAttribute('type'), 'index': stops[i].getAttribute('index'), 'content': decodeHTML(stops[i].getAttribute('content')), 'tip': getXMLdata( stops[i].getElementsByTagName('label')[0] ) } );
			this._markers[i] = marker;
			this._map.addOverlay( marker );
		}
		
		if ( (this.path && this.path.length > 0) )
			this.setPath( this.path );
		
		if (this.link)
		if (this.link.length)
			this.addEvent('select', function() { self.location.href = this.link; }.bind(this) );
		
		this.build();
	},
	
	add: function( params )
	{
		this.clean();
		var index = this._markers.length;
		var marker = new Point( params.point, { 'type': (params.icon ? params.icon : 'stop'), 'index': index, 'content': (index+1) , 'draggable': (this._options.editable == 'true' ? true : false), 'noautogeo': params.noautogeo } );
		//marker.addEvent('drag', function() { this.parseDirections(); }.bind(this) );
		marker.addEvent('move', function(marker) { this.build(); this.fireEvent('marker-moved', [marker, this]); }.pass(marker, this) );
		marker.addEvent('select', function(marker, multiple) { this.fireEvent('marker-selected', [marker, this, multiple]); }.bind(this) );
		marker.addEvent('remove', function(marker) { this.fireEvent('marker-removed', [marker, this]); }.pass(marker, this) );
		if (params.noGeo != true)
			marker.addEvent('geo', function(marker) { this.fireEvent('marker-geo', [marker, this]); }.pass(marker, this) );
		this._markers[index] = marker;
		
		this._map.addOverlay( this._markers[index] );
		
		//this.build();
		this.fireEvent('marker-added', [marker, this] );
	},
	
	build: function( )
	{
		this.clean();
		if (this._options.path)
		{
			var encoder = new PolylineEncoder();
			var decoding = encoder.decode(this._options.path, this._options.levels);
			this._overlay = new google.maps.Polyline( decoding.points );
			//this._overlay = new google.maps.Polyline( [new google.maps.LatLng(22.938159639316396, -80.5517578125), new google.maps.LatLng(20.46818922264095, -76.17919921875)] );
			this.parsePolyline( );
			this._map.addOverlay( this._overlay );
			this._overlay.show();
			this._options.path = null;
		}
		else
		{
			if (this._markers.length > 1)
			{
				this.direct = true;
				this.main.alert('Creazione itinerario in corso...', 0);
				this._dir.load(this.getString(this._start, this._end), {
					"getPolyline": true,
					"getSteps": true
				} );
			}
		}
	},

	destroy: function( )
	{
		this.main.cleanTrip( this );
		this.fireEvent('removed');
		/*this._markers.each(function(marker){
			marker.select(true);
		}.bind(this) )
		this.launchRemove();*/
	},
	
	parsePolyline: function( )
	{
		this.setStyle(this._overlay, this._style);
		new google.maps.Event.addListener(this._overlay, "click", this.select.bind(this) );
	},
	
	buildDirections: function(from, to) {
		this.direct = false;
		this._from = from;
		this._to = to;
		this._dir.load(this.getString(this._from, this._to), {
			"getPolyline": true,
			"getSteps": true
		} );
		/*this._dir.loadFromWaypoints(this.getWaypoints(this._from, this._to), {
			"getPolyline": true,
			"getSteps": true
		} );*/
		
	},
	
	getWaypoints: function(start, end, addwaypoint) {
		var waypoints = new Array();
		waypoints[0] = start;
		for (var i=0; i<this._waypoints.length; i++)
			waypoints[waypoints.length] = this._waypoints[i].getLatLng();
		if (addwaypoint)
			waypoints[waypoints.length] = addwaypoint.getLatLng();
		waypoints[waypoints.length] = end;
		return waypoints;
	},
	
	/*getString: function(start, end, addwaypoint)
	{
		var string = 'from: '+((typeof(start)=='string') ? start : start.lat()+','+start.lng() );
		for (var i=0; i<this._waypoints.length; i++)
			string += ' to: '+this._waypoints[i].getLatLng().lat()+','+this._waypoints[i].getLatLng().lng();
		if (addwaypoint)
			string += ' to: '+addwaypoint.getLatLng().lat()+','+addwaypoint.getLatLng().lng();
		string += ' to: '+((typeof(end)=='string') ? end : end.lat()+','+end.lng() );
		return string;
	},*/
	
	getString: function( )
	{
		var i = 0;
		var string = '';
		this._markers.each( function( marker ) {
			if (i == 0)
				string = 'from: '+marker.getLatLng().lat()+','+marker.getLatLng().lng();
			else
				string += ' to: '+marker.getLatLng().lat()+','+marker.getLatLng().lng();
			i++;
		} );
		return string;
	},
	
	getBoundaries: function()
	{
		var maxVertex = 999;
		if (this._nVertex > maxVertex)
			var addIndex = this._nVertex / maxVertex;
		else
			var addIndex = 1;
		var pieces = new Array();
		pieces[0] = this.roundCoord(this._markers[0].getLatLng().lat()) + '_' + this.roundCoord(this._markers[0].getLatLng().lng());
		for (var i=0; i<this._nVertex; i+=addIndex)
		{
			var k = parseInt( i );
			var v = this._points[k];
			pieces[ pieces.length ] = this.roundCoord(v.lat()) + '_' + this.roundCoord(v.lng());
		}
		return pieces;
	},
	
	getBounds: function()
	{
		if (this._overlay)
		{
			var bounds = this._overlay.getBounds();
			return {'sw': bounds.getSouthWest(), 'ne': bounds.getNorthEast() }
		}
	},
	
	setPath: function( content )
	{
		var pt = content.split( this._trigger );
		if (pt[0])
		{
			this._options.path 		= pt[0];
			this._options.levels 	= pt[1];
		}
		else
		{
			this._options.path 		= null;
			this._options.levels	= null;
		}
	},
	
	getPath: function( )
	{
		if (this._overlay)
		{
			this.getPathPoints();
			var encoder = new PolylineEncoder();
			var encoding = encoder.encode(this._points);
			return encoding.encodedPoints + this._trigger + encoding.encodedLevels;
		}
	},
	
	getPathPoints: function()
	{
		this._nVertex = this._overlay.getVertexCount();	
		this._points.length = 0;
		for (var i=0; i<this._nVertex; i++)
		{
			var v = this._overlay.getVertex(i);
			this._points[ this._points.length ] = v;
		}
	},
	
	getSummary: function( index )
	{
		var summary = '';
		if (index > 0)
		{
			this._nRoutes = this._dir.getNumRoutes();
			if (this._nRoutes > 0)
			{
				var route = this._dir.getRoute(index-1);
				var nSteps = route.getNumSteps();
				if (nSteps > 0)
				{
					var routeXML = '<route distance="'+route.getDistance().meters+'" duration="'+route.getDuration().seconds+'">';
					for (var i=0; i<nSteps; i++)
					{
						var step = route.getStep(i);
						routeXML += '\n<step>\n\t<index>' + step.getPolylineIndex() + '</index>\n\t<lat>'+step.getLatLng().lat()+'</lat>\n\t<lng>'+step.getLatLng().lng()+'</lng>\n\t<distance>'+step.getDistance().meters+'</distance>\n\t<duration>'+step.getDuration().seconds+'</duration>\n\t<summary>'+step.getDescriptionHtml()+'</summary>\n</step>';
					}
					routeXML += '</route>';
				}
				summary += routeXML;
			}
		}
		return summary;
	},
	
	getDistance: function( index )
	{
		if (index > 0)
		{
			switch (this._dir_mode)
			{
				case 'streets':
					this._nRoutes = this._dir.getNumRoutes();
					if (this._nRoutes > 0)
					{
						var route = this._dir.getRoute(index-1);
						return parseInt(route.getDistance().meters / 1000);
					}
				break;
				case 'streight':
					if (this._overlays[index-1])
					{
						var meters = this._overlays[index-1].getLength();
						return parseInt(meters / 1000);
					}
				break;
			}
		}
		else
			return 0; // start...no distance
	},
	
	parseDirection: function()
	{
		this._dir_mode = 'streets';
		this.clean();
		if (!this.direct)
			this.convertDirections();
		this._overlay = this._dir.getPolyline();
		if (this._overlay)
		{
			this.parsePolyline( );
			this.getPathPoints( );
			this._map.addOverlay( this._overlay );
		}
		this.main.closeAlert();
		this.fireEvent('changed').fireEvent('success');
		//this.getBoundaries();
	},
	
	errorsDirections: function(dir) {
		// straight polyline
		this._dir_mode = 'streight';
		
		var points = new Array();
		this._markers.each( function( marker ) {
			points[ points.length ] = marker.getLatLng();
		} );
		
		this._overlays.length = 0;
		points.each( function( point, i ) {
			if (i < (points.length-1))
			{
				var streight = [ points[i], points[i+1] ];
				var spoly = new google.maps.Polyline( streight );
				this._overlays[ this._overlays.length ] = spoly;
				//this._map.addOverlay( spoly );
			}
		}.bind(this) );
		this._overlay = new google.maps.Polyline( points );
		this.parsePolyline();
		this._nVertex = 0;
		this._map.addOverlay( this._overlay );
		
		///
		var status = dir.getStatus().code;
		var error;
		if (status == G_GEO_UNKNOWN_ADDRESS)
			error = "No corresponding geographic location could be found for one of the specified addresses. This may be due to the fact that the address is relatively new, or it may be incorrect.\nError code: " + status;
		else if (status == G_GEO_SERVER_ERROR)
			error = "A geocoding or directions request could not be successfully processed, yet the exact reason for the failure is not known.\n Error code: " + status;
		else if (status == G_GEO_MISSING_QUERY)
			error = "The HTTP q parameter was either missing or had no value. For geocoder requests, this means that an empty address was specified as input. For directions requests, this means that no query was specified in the input.\n Error code: " + status;
		//else if (gdir.getStatus().code == G_UNAVAILABLE_ADDRESS)  <--- Doc bug... this is either not defined, or Doc is wrong
			//error = "The geocode for the given address or the route for the given directions query cannot be returned due to legal or contractual reasons.\n Error code: " + status;
		else if (status == G_GEO_BAD_KEY)
			error = "The given key is either invalid or does not match the domain for which it was given. \n Error code: " + status;
		else if (status == G_GEO_BAD_REQUEST)
			error = "A directions request could not be successfully parsed.\n Error code: " + status;
		else
			error = "Non è presente cartografia stradale,<br />il percorso sarà approssimato";
		
		this.fireEvent('changed').fireEvent('error');
		this.main.alert(error, 1);
	},
	
	distance: function( )
	{
		if (this._dir)
		{
			var dist = this._dir.getDistance();
			return parseInt(dist.meters / 1000);
		}
		return '';
	},
	
	convertDirections: function() {
		var dir = this._dir;
		var maxRoute = dir.getRoute(dir.getNumRoutes()-1);
		this.start(dir.getRoute(0).getStep(0).getLatLng());
		this.end(maxRoute.getStep(maxRoute.getNumSteps()-1).getLatLng());
	},
	
	setStyle: function( polyline, style )
	{
		polyline.color = this._styles[style].color;
		polyline.weight = this._styles[style].weight;
		polyline.opacity = this._styles[style].opacity;
	}
});