/* DoggieMaps.js starts */
/**
* Google maps abstraction for doggie wonderland
* requires google maps v3 api to be loaded before userProfile
* eg <script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script>
**/

/**
* http://gmaps-samples-v3.googlecode.com/svn/trunk/drivingdirections/directions-optimized.html
*http://gmaps-samples-v3.googlecode.com/svn/trunk/localsearch/places.html
*
*http://code.google.com/apis/maps/documentation/v3/reference.html
*http://code.google.com/apis/maps/documentation/v3/services.html
**/

var letters = ['A' , 'B' , 'C', 'D' , 'E' , 'F' , 'G' ,'H' , 'I' , 'J' , 'K' , 'L' , 'M' , 'N' , 'O' , 'P' , 'Q' , 'R' , 'S', 'T', 'U' , 'V' ,'W' , 'X', 'Y' , 'Z'];


function DoggieMaps()
{
// construct
	
}

// reference to doggiemaps obj
var dmobj;

/**
* Function init
* Must be called before use 
* @param canvas:DOM object = div assigned to hold map canvas
* @param latlng:String = comma seperated lat/lng : Default is center of NZ
* @param zoom:int = zoom level : Default is 6 (zoomed out nz)
**/
DoggieMaps.prototype.init = function( canvas , latlng , zoom)
{
	this.canvas = canvas;
	this.offset = -300;
	this.offsety = 0;
	this.defaultZoom = 16;
	dmobj = this;
	onResize();
	
	this.markerArray = [];
		
	if(!zoom) var zoom = 5;
	if(!latlng) var latlng = '-42.078654,173.671875';
	
    var myOptions = {
      zoom: zoom,
      center: this.convertStringToLatLng(latlng),
      mapTypeControl:false,
      navigationControl: true,
      scrollwheel: false,
      navigationControlOptions: {
        position: google.maps.ControlPosition.TOP_RIGHT
      },
      mapTypeId: google.maps.MapTypeId.ROADMAP
    };
    this.map = new google.maps.Map(canvas, myOptions);
    panmap();
    this.init = false;
    
    google.maps.event.addListener(this.map, 'zoom_changed', function() {
    	// nothing for now
  	});

 	window.onresize = function(){onResize();}
 	window.onscroll = function(){onResize();}
 	
 	var geo = canvas.getAttribute('data-geo');
 	var search = canvas.getAttribute('data-search');
 	// if geo data present... will not search
 	if(geo)
 	{
 		this.goto({latlng:geo}, true);
 	}
 	else if(search)
 	{
 		this.search(search);
 	}
 	
 	
 	// add find location functionality
 	var findButton = $('button#find_location');
 	if(findButton)
 	{
 		
 		findButton.click(function(){
 		
 			var searchString = '';
 			
 			var address = $('#street_address').attr('value');
 			if(address) searchString += address;
 			var suburb =$('#suburb').attr('value');
 			if(suburb) searchString += ', '+suburb;
 			var city=$('#city').attr('value');
 			if(city) searchString += ', '+city;
 			
 			if(searchString != '') dmobj.search( searchString );
 		});
 	}
 	
}

/**
* Function goto
* Goto a specific lat/lng
* @param location:Object = {latlng , name , image}
* @param zoom:int = zoom for map : default is current zoom
* @param marker:Boolean = show marker or not.. default is false
* @param noClear:Boolean = if true won't clear trip
**/
DoggieMaps.prototype.goto = function(location , marker , zoom , noClear)
{
	if(!noClear) this.clearTrip();
	if(!zoom) var zoom = this.defaultZoom;
	var latlng = location.latlng;
	if(typeof(latlng)=='string') {
		latlng = this.convertStringToLatLng(latlng);
	}
	this.map.setZoom(zoom);
	this.map.panTo(latlng);
	onResize();
	panmap();
	this.clearMarkers();
	if(this.directionRenderer)
	{
		this.directionRenderer.setMap(null);
		this.directionRenderer.setPanel(null);
	}
	if(marker) this.setMarker(location);
}

/***
* Function search
* Searches for a location based on an address search, zooms map to first result
* @param address:String = address string to search
**/
DoggieMaps.prototype.search = function( address )
{
	this.clearTrip();
	if(!this.geocoder) this.geocoder = new google.maps.Geocoder();
	this.geocoder.geocode(
	{
		'address':address,
		'bounds':new google.maps.LatLngBounds(this.convertStringToLatLng('-47.468702,164.663086'), this.convertStringToLatLng('-33.408211,-179.868164'))
	}, 
	function(results , status){
		if(status == 'OK')
		{
			dmobj.goto( {latlng:results[0].geometry.location , name:address } , true);
		
			// populate hidden field
			var geo = $('input#geo');
			if(geo)
			{
				var loc =  results[0].geometry.location;
				geo.attr('value' , loc.b+','+loc.c);
			}
		}else{
			alert('Sorry, there were no google maps results found. Please try refining your search');
		}
	});
}


// 


/***
* Function makeTrip
* creates a brand spanking new trip you can add points to later
* @param points:Array = array of location objects in the format {latlng , name , image , id}
* @param panel:DOM object = the div to display the resutls
**/
DoggieMaps.prototype.makeTrip = function(points , panel , drags)
{


	if(!drags) drags = false;
	this.draggable = drags;
	
	this.clearTrip();
	for(var i = 0;i<points.length;i++)
	{
		// convert to latlng objects
		points[i].latlng = this.convertStringToLatLng(points[i].latlng);
		
		this.currentTrip.push( points[i] );	
	}
	if(!this.directionsService) this.directionsService = new google.maps.DirectionsService();
	
	this.directionPanel = panel;
	
	if(points.length > 1)
	{
		this.route();
	}else{
		this.goto( points[0] , true , this.defaultZoom , true);
	}
}

/**
* Function route
* shows the route...
*/
DoggieMaps.prototype.route = function()
{	
	this.clearMarkers();
	if(this.directionRenderer)
	{
		this.directionRenderer.setMap(null);
		this.directionRenderer.setPanel(null);
	}
	var waypoints = [];
	
	for(var i = 0;i<this.currentTrip.length;i++)
	{
		if(i != 0 && i != this.currentTrip.length-1) waypoints.push({location:this.currentTrip[i].latlng});
	}
	this.directionsService.route( 
	{
  		origin: this.currentTrip[0].latlng,
 		destination: this.currentTrip[this.currentTrip.length-1].latlng,
 	 	travelMode: google.maps.DirectionsTravelMode.WALKING,
 		waypoints: waypoints,
 		optimizeWaypoints: true,
 		provideRouteAlternatives: false,
	  	avoidHighways: true,
	  	avoidTolls: true
	} , 
	function(results , status){
		dmobj.showRoute(results);
	});
}

/***
* Function addToTrip
* Must have called makeTrip first
* @param location:Object - {latlng , name  , image , id}
* @param index:Number = index to add point at, default is end
* @param noRoute:Boolean = make this true if you DON'T want to render the trip after adding the location to it. Default is false
*/
DoggieMaps.prototype.addToTrip = function(location , index , noRoute)
{
	if(index!=null)
	{	
		this.currentTrip.splice(index , 0 ,location );
	}else{
		this.currentTrip.push(location);
	}
	if(!noRoute) this.route();
}

/**
* Function removeFromTrip
* @param location:Object - {latlng , name  , image , id}. Only need the location.id property
**/
DoggieMaps.prototype.removeFromTrip = function(id)
{
	var list = $('.trip_list').find('div[id='+id+']');
	list.slideDown(300,function(){
		$(this).remove();
	});
	
	for(var i = 0;i<this.currentTrip.length;i++)
	{
		if(this.currentTrip[i].id == id)
		{
			this.currentTrip.splice(i , 1);
			this.directionPanel.style.visibility = 'hidden';
			
			
			
			if(this.currentTrip.length > 1)
			{
				this.route();
			}else{
				window.location.reload();
			}
			
			break;
		}
	}
}

/***
* Function reorderTrip
* @param from:Number = current index of point
* @param to:Number = destination index of point
**/
DoggieMaps.prototype.reorderTrip = function(from , to)
{
	var drags = $('.adp-placemark');
	
	$('.adp-placemark').unbind( "dragstop");
	
	drags.draggable("destroy" );
	
	if(this.currentTrip.length)
	{
		
		this.directionPanel.style.visibility = 'hidden';
		var temp = this.currentTrip[from];
		this.currentTrip[from] = this.currentTrip[to];
		this.currentTrip[to] = temp;
		
		
		// call ajax to update record
		var i = 0;
		var newOrder = [];
		var script = this.directionPanel.getAttribute('data-saveurl');
		for(;i<this.currentTrip.length;i++)
		{
			newOrder.push(this.currentTrip[i].id);
		}
		
		// send newOrder array to script
		
		if(script)
		{
			$.ajax({url:script,
					type:'POST',
					data:{data:newOrder},
					success: function(data) {
   						dmobj.route();
  					}
			});
		}
		
	}
}


/***
* Function showRoute
* @param results:DirectionsResult 
**/
DoggieMaps.prototype.showRoute = function(results)
{
	
	if(!this.directionRenderer) {
		this.directionRenderer = new google.maps.DirectionsRenderer({
			suppressMarkers:true,
			polylineOptions:{strokeColor:'#2eb6e8' , strokeOpacity:0.7 , strokeWeight:6}
		});	
	}
	this.directionPanel.style.visibility = 'visible';
	this.directionRenderer.setMap(this.map);
	this.directionRenderer.setPanel(this.directionPanel);
	this.directionRenderer.setDirections(results);
	
	setTimeout( panmap , 100);
	setTimeout(onResize , 100);

	if(this.draggable) setTimeout(makeSortable , 20);
	setTimeout(showMarkers , 30)
	
		
}
/**
* Swaps out markers on the map and results panel and adds remove buttons
*/
function showMarkers()
{
	
	var loc;
	var temp = [];
	var places = $('td.adp-text[jstcache|=11]');
	var pl;
	for(var i = 0;i<dmobj.currentTrip.length;i++)
	{
		loc = {latlng:dmobj.currentTrip[i].latlng , image:unescape(dmobj.currentTrip[i].image) , name:dmobj.currentTrip[i].name , id:dmobj.currentTrip[i].id};
		if(!loc.image) loc.image = 'http://maps.gstatic.com/intl/en_us/mapfiles/icon_green'+letters[i]+'.png';
		
		dmobj.setMarker(loc);
		temp.push(loc);
		
		pl = places[i];
		if(loc.name) pl.innerHTML = loc.name+'<div class="trip_remove" style="float:right;"></div>';
		$(pl).attr('data_index' , loc.id);
	}
	
	var results = $('img[jstcache|=13]');
	i=0;
	results.each(function(index){
		if($(this).attr('src'))
		{
			$(this).attr('src' , temp[i].image );
			i++;
		}
	});
	
	
	// add remove functionality
	var caption = $('.tooltip');
			$('.trip_remove').mouseenter( function(){ 

				$(caption).css('display','block').html('remove?');
				$(caption).css('top' , $(this).offset().top - 25);
				$(caption).css('left' , $(this).offset().left -4);

			});

			$('.trip_remove').mouseleave( function(){
				$(caption).css('display','none');
			});
			
			$('.trip_remove').click(function(){
			var id = $(this).parent().attr('data_index');
			
			var script = dmobj.directionPanel.getAttribute('data-removeurl');
		
			if(script)
			{
			
				$.ajax({url:script,
					type:'POST',
					data:{data:id},
					success: function(data) {
   						dmobj.removeFromTrip(id);
  					}
				});
				
				
			}
			
		});
}

/**
* Make the results panel sortable and re-draws route
*/
function makeSortable()
{
	
	
	var drags = $('.adp-placemark');
	var positions = [];
	drags.each(function(index) {
		positions.push($(this));
		//.offset().top);
  	});
  	
  	// remove last item
  	positions.splice( positions.length-1 , 1);

	drags.draggable({containment:'#directions' , axis:'y' , revert:true, revertDuration:100, scroll:true });
	
	$('.adp-placemark').bind( "dragstop", function(event, ui) {
		var ind;
		var newind;
		var i = 0;
		for(i = 0;i<positions.length;i++)
		{
			if(positions[i][0] == ui.helper[0]) 
			{ 
				ind = i;
			}
		}
		
		if(ui.offset.top > positions[ind].offset().top)
		{
			// direction = down
			newind = 0;
			for(i = 0;i<positions.length-1;i++)
			{
				if(ui.offset.top > positions[i+1].offset().top){
					newind++;
				}
			}
		}
		else
		{
			// direction = up
			newind = positions.length-1;	
			for(i = positions.length-1;i>0;i--)
			{
				if(ui.offset.top < positions[i-1].offset().top){
					newind--;
				}
			}
		}
		
		if(ind != newind)
		{
			dmobj.reorderTrip(ind , newind);
		}		
		
	});

}

function panmap(){
	dmobj.map.panBy(dmobj.offset,dmobj.offsety);
}

/**
* Function clearTrip
**/
DoggieMaps.prototype.clearTrip = function()
{
	this.clearMarkers();
	this.currentTrip = [];
	if(this.directionRenderer)
	{
		this.directionRenderer.setMap(null);
		this.directionRenderer.setPanel(null);
	}
}

/**
* Function clear markers
**/
DoggieMaps.prototype.clearMarkers = function()
{
	
	for(var i = 0;i< this.markerArray.length;i++)
	{
		this.markerArray[i].setMap(null);
	}
	this.markerArray = [];
}

/**
* Function setMarker
* Sets a marker at the sepcified latlng
* @param location:Object = {latlng , name  , image}
**/
DoggieMaps.prototype.setMarker = function(location)
{
	var latlng = location.latlng;
	if(typeof(latlng)=='string') {
		latlng = this.convertStringToLatLng(latlng);
	}
	
	var marker = new google.maps.Marker({
		map:this.map,
		position:latlng,
		title:location.name
		
	});
	
	if(location.image) marker.setIcon(location.image);
	this.markerArray.push(marker);
}

/////// internal functions ////////
/**
* Function convertStringToLatLang
**/
DoggieMaps.prototype.convertStringToLatLng = function(latlng)
{
	var llarr = latlng.split(',');
	var ll = new google.maps.LatLng(llarr[0] , llarr[1]);
	return ll;
}

/** 
* Function resize
* needs to be called when browser is resized and setting size of canvas at init
**/
onResize = function()
{
	var sTop = $(window).scrollTop();
	dmobj.canvas.style.width = $('body').width()+'px';
	var top = -sTop+195;
	if(top < 0) top = 0;
	dmobj.canvas.style.top = top+'px';
	if(sTop <195) sTop = 195;
	var theheight = $('#wrap').innerHeight()-sTop-60;
    dmobj.canvas.style.height = theheight+'px';
    if(dmobj.map) google.maps.event.trigger(dmobj.map, 'resize');
}




