/*

JMoooney@saxotech.com 06.06.08
A few test function for making the javascript code compute distances,
and sort the results in the client ... 

These are just for the prototype ... pretty please don't give to a customer.

*/

function NewSaxList()
{
this.detByObj = {};
this.theList =[];
this.saxlisterror ="";
// Set a default origin (this is the white house for our demo ..
//'33.836662','-118.341662'
this.dlat ='33.836662';
this.dlon ='-118.341662';
this.orgchflag =0; // flag for tracking origin changes after load
this.featuredAvertiser =0; //flag to set the orign on the featured advertiser
this.listTable =[];;
return this;
}


//instantiate list object object ....
var saxlist = new NewSaxList();

//setup some custom icons ...
   var iconGreen = new GIcon(); 
    //iconGreen.image = 'http://gmaps-samples.googlecode.com/svn/trunk/markers/circular/greencirclemarker.png';
    iconGreen.image = '/images/cityguide/pinFeatured.png';
    iconGreen.shadow = '/images/cityguide/pinShadow.png';
    iconGreen.iconSize = new GSize(30, 30);
    iconGreen.shadowSize = new GSize(0, 0);
    iconGreen.iconAnchor = new GPoint(0, 0);
    iconGreen.infoWindowAnchor = new GPoint(5, 15);

    var iconBlue = new GIcon(); 
    //iconBlue.image = 'http://gmaps-samples.googlecode.com/svn/trunk/markers/circular/bluecirclemarker.png';
    iconBlue.image = '/images/cityguide/pinCourtesy.png';
    iconBlue.shadow = '/images/cityguide/pinShadow.png';
    iconBlue.iconSize = new GSize(30, 30);
    iconBlue.shadowSize = new GSize(0, 0);
    iconBlue.iconAnchor = new GPoint(0, 0);
    iconBlue.infoWindowAnchor = new GPoint(5,15);
    
    var iconDefault = new GIcon(); 
    //iconBlue.image = 'http://gmaps-samples.googlecode.com/svn/trunk/markers/circular/bluecirclemarker.png';
    iconDefault.image = '/images/marketplace/GoogleMapsPin.png';
    iconDefault.shadow = '/images/marketplace/dot.gif';
    iconDefault.iconSize = new GSize(25, 37);
    iconDefault.shadowSize = new GSize(0, 0);
    iconDefault.iconAnchor = new GPoint(13, 37);
    iconDefault.infoWindowAnchor = new GPoint(5,15);
    
NewSaxList.prototype.openBubble = function(marker,idx,biz)
	{
	return function() {
					 		try {
            			marker.openInfoWindowHtml("<strong>&nbsp;"+biz+"</strong>");
            		}
            		catch(gerror)
            			{
            			alert(gerror.message+" scope="+(typeof marker)+idx);	
            			}
           }
	}    

NewSaxList.prototype.linkToBubble = function(handler, biz,objId,idx)
{
	
	try
	{
	var listItem = document.createElement('li');
	
  listItem.innerHTML = '<a href="#">' + biz + '</a>';
  listItem.getElementsByTagName('a')[0].onclick = handler;
  
  var markerItem = document.getElementById("marker_"+objId);
  //var imgstring = '<span class="markerIdx">'+(idx+1)+'</span><img src="/images/cityguide/pinFeatured2.gif">';
  var imgstring = '<img src="/images/marketplace/GoogleMapsPin2.png" border="0">';
  markerItem.innerHTML = '<a href="#">' +imgstring+ '</a>';
  listItem.getElementsByTagName('a')[0].onclick = handler;
  markerItem.getElementsByTagName('a')[0].onclick = handler;
	document.getElementById('pinlist').appendChild(listItem);
  }
  catch(error)
  	{
  	this.saxlisterror+="link to bubble error: "+error.message+"\n";	
  	}


}

// a function for creating the marker ...

NewSaxList.prototype.createMarker = function(lat,lng,biz,idx)
   {
   	var mycon=(idx < 10) ? iconDefault : iconBlue;
   	opts = {
    "icon": iconDefault,
    "clickable": true,
    // "labelText": (idx+1),
    "labelClass": "markerLabel",
    "labelOffset": new GSize(8,8)
  	};
 
    var marker = new LabeledMarker(new GLatLng(lat,lng), opts);
    var bubble =  this.openBubble(marker,idx,biz);
    var theId =this.theList[idx];
    this.linkToBubble(bubble,biz,theId,idx);
		GEvent.addListener(marker, "click",bubble);
   	return marker;
   }	


NewSaxList.prototype.init = function(lt,lg)
{
// check to see if there are any errors in the  creation of the js obect 
// when building from the CCE list 
if (lt && lg)
		{
		this.dlat =lt;
		this.dlon =lg;
		}
if (this.saxlisterror)
		{
		alert(this.saxlisterror);
		}
else
		{	
    // call roll-up function for looping the listings, calculating the distance 
    // AND writing out the distances for each object in the list
		this.calculateDistance();
		 
		if (this.saxlisterror)
		{
		alert(this.saxlisterror);
		}
   }
	
  };
NewSaxList.prototype.calculateDistance = function ()
{
	try {
		// call map functions in mapFuncs.js
		
		if (this.theList.length > 0 && !this.orgchflag && this.featuredAvertiser !=0)
			{
			// if we have featured advertiser's center map on the first in the list	
			try
			{
			var cId = this.theList[0];
			var clat   = this.detByObj[cId].lat;
		  var clng   = this.detByObj[cId].lng;
		  setupMap(clat,clng);
			}
			catch(error)
					{
						alert("failed "+error.message);
						setupMap(this.dlat,this.dlon);
					}
			}
			else
			{
			setupMap(this.dlat,this.dlon);
		  }
}
catch (error)
		{
		this.saxlisterror+="map setup problems: "+error.message+"\n";
		}
		
	var allmarkers= [];
	 var bounds = new GLatLngBounds();
	for (var i=0; i < this.theList.length; i++)
				{
					var theId = this.theList[i];
				try
					{
					var lat   = this.detByObj[theId].lat;
					var lng   = this.detByObj[theId].lng;
					var bizname = this.detByObj[theId].bizname;
				 		// try to add a marker for adding to the marker manager
				 try {
				 	       
				 	       
				 	       var latlng =new GLatLng(lat,lng);
				 			   bounds.extend(latlng);
				 	  
				 	  
				 		if (this.detByObj[theId].upsell1 != 99)
				 				{
				 				//alert(bizname);
				 				
				 				var m = this.createMarker(lat,lng,bizname,i);
				 				if (typeof m != "undefined")
				 					{
					 				allmarkers.push(m);
					 			  } 
					 			
					 		  }
					 			
					  }
					  catch(gerror)	
					  		{
					  	  this.saxlisterror+="add marker error: "+gerror.message+"\n";
					  		}

								var dist  = this.distHaversine(lat,lng,this.dlat,this.dlon);
					//this.listTable.push({distance:dist,cceid:theId,rating:this.detByObj[theId].rating});
					this.listTable[i]={
								distance:dist,
								cceid:theId,
								rating:this.detByObj[theId].rating,
								upsell1: this.detByObj[theId].upsell1
								};
					// removed dynamic distance write now supplied on server ..
					// this.writeDistance(dist,theId);
				}
				catch(err)
						{
								var lat   = this.detByObj[theId].lat;
								var lng   = this.detByObj[theId].lng;
									this.saxlisterror += "("+lat+","+lng+"error:"+ err.message+'\n';
						}
					
				}
				
				try 
					{
						//alert(allmarkers.length);
						mgr = new MarkerManager(map);
  					mgr.addMarkers(allmarkers, (allmarkers.length > 0) ? map.getBoundsZoomLevel(bounds) : 8);
  					//alert("Marker count:"+mgr.getMarkerCount(12));
  					mgr.refresh();
  					map.setZoom((allmarkers.length > 0) ? map.getBoundsZoomLevel(bounds) : 10);
  					if (allmarkers.length > 0) { map.setCenter(bounds.getCenter()); }
  					if (document.basicSearchForm.txtSearch.value !="")
  							{
  							// this.dynamicSort([],20);	
  							//this.quickSort();
  						  }
					}
				catch(gerror)
						{
						this.saxlisterror+="markermanager error: "+gerror.message+"\n";
						}
					
	
}


NewSaxList.prototype.paginateList = function(pageIdx)
{
try
{
var listbox = document.getElementById("listcontainer");
/*
			if(listbox.hasChildNodes()) {
			while(listbox.childNodes.length >= 1 ) {
			listbox.removeChild(listbox.firstChild);
			}
		}
*/
   listbox.innerHTML = '<div id="listControlsLeft"></div><br><br>';
   
	for (var t=0; t<this.listNodes[pageIdx].length; t++)
			{
		  listbox.appendChild(this.listNodes[pageIdx][t]);		
			}
this.drawPageNav(pageIdx);
}
catch(perr)
			{
			alert("paginatelist error: "+perr.message+"\n");
				this.saxlisterror+="paginatelist error: "+perr.message+"\n";
			}	
	
}

NewSaxList.prototype.drawPageNav = function(curIdx)
{
try
{
var n ="";
var p ="";
var firsthit = (curIdx * this.itemsPerPage)+1;
var lasthit =  firsthit+this.listNodes[curIdx].length;
var totalhits = this.listTable.length;
var countinfo = firsthit+' through '+lasthit+ ' of '+totalhits; 
if ((curIdx+1) <= this.listNodes.length)
		{
		n = "javascript:saxlist.paginateList("+(curIdx+1)+");";
		n = '<a href="'+n+'"><img src="/images/cityguide/searchNext.gif" border="0" class="searchNav" /></a>';
		}
if ((curIdx-1) > -1)
		{
		p = "javascript:saxlist.paginateList("+(curIdx-1)+");";
		p = '<a href="'+p+'"><img src="/images/cityguide/searchPrev.gif" border="0" class="searchNav" /></a>&nbsp;&nbsp;';
		}

var nav =p+countinfo+n;		
document.getElementById("listControlsLeft").innerHTML = nav;		

}
catch(err)
		{
		this.saxlisterror+="drawPageNav error: "+err.message+"\n";	
		}

}

NewSaxList.prototype.dynamicSort = function(orderByFields,itemsPerPage)
{
try 
{
this.listNodes = [];
/*
if (instanceof orderByFields = "Array")
	{
	this.listTable.objSort(orderByFields);
	}
else
	{
	this.listTable.objSort("upsell1","distance","cceid");
	}
*/
this.itemsPerPage = itemsPerPage;
this.listTable.objSort("upsell1","distance","cceid");
var pg =0;
this.listNodes[pg] = [];
var base =itemsPerPage;
var pageInc =0;
	for (var i=0; i < this.listTable.length; i++)
				{
        	if (i == itemsPerPage)
        			{
        			pageInc=0;
        			//this.saxlisterror += "incrementing page count counter="+i+"\n";
        			itemsPerPage +=base;
        			pg++;
        			this.listNodes[pg] = [];
        			//this.saxlisterror += "\n incrementing page count counter="+i+"\n last page length="+this.listNodes[(pg-1)].length;
        			}
        	var cceid = this.listTable[i].cceid;
        	var sc =document.getElementById("item_"+cceid);
					var scParent = sc.parentNode;
					this.listNodes[pg][pageInc] = sc.parentNode.removeChild(sc);
					pageInc++;
			  }
		//alert(listNodes.length);
		
				this.paginateList(0);
}
catch(err)
		{
	  
		this.saxlisterror+="dynamicsort error: "+err.message+" page="+pg+"\n";
	}
}


NewSaxList.prototype.quickSort = function()
{
try 
{
var listNodes = [];
this.listTable.objSort("upsell1","distance","cceid");
	for (var i=0; i < this.listTable.length; i++)
				{
        	var cceid = this.listTable[i].cceid;
        	var sc =document.getElementById("item_"+cceid);
					var scParent = sc.parentNode;
					listNodes.push(sc.parentNode.removeChild(sc));
			  }
		//alert(listNodes.length);
	var listbox = document.getElementById("listcontainer");
	for (var t=0; t<listNodes.length; t++)
			{
		  listbox.appendChild(listNodes[t]);		
			}
	
}
catch(err)
		{
		this.saxlisterror+="quicksort error: "+gerror.message+"\n";
	}
}

NewSaxList.prototype.setLatLong = function(newlatlong)
{
this.orgchflag =1;
this.dlat = newlatlong[0].toString();
this.dlon = newlatlong[1].toString();	

try
		{
		document.basicSearchForm.Latitude.value = newlatlong[0];
		document.basicSearchForm.Longitude.value = newlatlong[1];
		}
	catch(error)
			{
				alert(error.message);
			}
	
}



/*
 * Use Haversine formula to Calculate distance (in km) between two points specified by 
 * latitude/longitude (in numeric degrees)
 *
 * example usage from form:
 *   result.value = LatLon.distHaversine(lat1.value.parseDeg(), long1.value.parseDeg(), 
 *                                       lat2.value.parseDeg(), long2.value.parseDeg());
 * where lat1, long1, lat2, long2, and result are form fields
 */
NewSaxList.prototype.distHaversine = function(lat1, lon1, lat2, lon2) {
	try
	{
	lat1=lat1.parseDeg();
	lon1=lon1.parseDeg();
	lat2=lat2.parseDeg();
	lon2=lon2.parseDeg();
  var R = 6371; // earth's mean radius in km
  var dLat = (lat2-lat1).toRad();
  var dLon = (lon2-lon1).toRad();
  lat1 = lat1.toRad(), lat2 = lat2.toRad();

  var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
          Math.cos(lat1) * Math.cos(lat2) * 
          Math.sin(dLon/2) * Math.sin(dLon/2);
  var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
  var d = R * c;
  return d;
		}
		  catch(err)
  		{
  		this.saxlisterror+= "from decodeDistance failed="+err.message+"\n";	
  		}
}

NewSaxList.prototype.writeDistance = function(theDistance,listId)
{
	try
	{
	d = parseFloat(theDistance);
	//don't convert to miles in Canada - PM (this should go into the globals)
	//d= d/1.6;
	
	if (!this.neworigin)
			{				
			// alert("distance_"+listId);
			document.getElementById("distance_"+listId).innerHTML = ""+d.toFixed(2)+" km.";
			}
	else
			{			
			// alert("distance_"+listId);
			document.getElementById("distance_"+listId).innerHTML = ""+d.toFixed(2)+" km.";
			//document.getElementById("distance_"+listId).innerHTML = ""+this.neworigin+ "~="+d.toFixed(2)+" mi.";
		  }	
			
	
  }
  catch(err)
  		{
  		this.saxlisterror+= "from writeDistance failed="+err.message+"\n";	
  		}
	
}

NewSaxList.prototype.addCoords = function(bizLat,bizLong,listId,coname,latlon,up1)
{
try
			{
			// setup a details object 
			if (latlon != "")
			{
					try {		
						//this.saxlisterror += latlon;
						
						var ar  = latlon.split(";");
						bizLat =ar[0];
						bizLong="-"+ar[1];	
						//this.saxlisterror += "latlong=Lat:"+bizLat+" Long="+bizLong+"\n";
						}
					catch(error)
							{
							this.saxlisterror += "bad split"+error.message+"\n";	
							}
				}	
				//alert(bizLat);alert(bizLong);
			this.detByObj[listId] = {};
			this.detByObj[listId].lat = bizLat;
		  this.detByObj[listId].lng = bizLong;
		  this.detByObj[listId].bizname = coname;
		  this.detByObj[listId].upsell1 = up1;
			// setup a an array of the ids for later indexing the detail object
			this.theList.push(listId);
		
					  
			}
catch(e)
			{
			this.saxlisterror +="from addCoords error="+ e.message+"\n";
			}	

}
NewSaxList.prototype.changeOrigin = function(address)
{
try
	{
	this.neworigin = address;
	var refObj =this;
	geocoder = new GClientGeocoder();	
	geocoder.getLatLng(address, function(point) 
		{
		if (!point)
				{
				alert("Sorry, google didn't give us a new point for the address");	
				}	
		else
			{
			
			eval("var newcoords = new Array"+point);
			refObj.setLatLong(newcoords);
			refObj.calculateDistance();
			}
		}
	
	);
	}
catch(err)
		{
		this.saxlisterror+="change origin error: "+err.message+"\n";
		alert(this.saxlisterror);
		}

}



String.prototype.parseDeg = function() {
  if (!isNaN(this)) return Number(this);                 // signed decimal degrees without NSEW

  var degLL = this.replace(/^-/,'').replace(/[NSEW]/i,'');  // strip off any sign or compass dir'n
  var dms = degLL.split(/[^0-9.]+/);                     // split out separate d/m/s
  for (var i in dms) if (dms[i]=='') dms.splice(i,1);    // remove empty elements (see note below)
  switch (dms.length) {                                  // convert to decimal degrees...
    case 3:                                              // interpret 3-part result as d/m/s
      var deg = dms[0]/1 + dms[1]/60 + dms[2]/3600; break;
    case 2:                                              // interpret 2-part result as d/m
      var deg = dms[0]/1 + dms[1]/60; break;
    case 1:                                              // decimal or non-separated dddmmss
      if (/[NS]/i.test(this)) degLL = '0' + degLL;       // - normalise N/S to 3-digit degrees
      var deg = dms[0].slice(0,3)/1 + dms[0].slice(3,5)/60 + dms[0].slice(5)/3600; break;
    default: return NaN;
  }
  if (/^-/.test(this) || /[WS]/i.test(this)) deg = -deg; // take '-', west and south as -ve
  return deg;
}
Number.prototype.toRad = function() {  // convert degrees to radians
  return this * Math.PI / 180;
}




/*

PM comments
This library extends the built in JS Array with a sortby method
similiar to a sql sort operation.

objSort v 1.1
copyright 2006 Thomas Frank

This program is free software under the terms of the 
GNU General Public License version 2 as published by the Free 
Software Foundation. It is distributed without any warranty.
*/

tfObjSort={
	init:function(){
		Array.prototype.objSort=function(){
			tfObjSort.setThings(this);
			var a=arguments;
			var x=tfObjSort;
			x.a=[];x.d=[];
			for(var i=0;i<a.length;i++){
				if(typeof a[i]=="string"){x.a.push(a[i]);x.d.push(1)};
				if(a[i]===-1){x.d[x.d.length-1]=-1}
			}
			return this.sort(tfObjSort.sorter);
		};
		Array.prototype.strSort=function(){
			tfObjSort.setThings(this);
			return this.sort(tfObjSort.charSorter)
		}
	},
	sorter:function(x,y){
		var a=tfObjSort.a
		var d=tfObjSort.d
		var r=0
		for(var i=0;i<a.length;i++){
			if(typeof x+typeof y!="objectobject"){return typeof x=="object"?-1:1};
			var m=x[a[i]]; var n=y[a[i]];
			var t=typeof m+typeof n;
			if(t=="booleanboolean"){m*=-1;n*=-1}
			else if(t.split("string").join("").split("number").join("")!=""){continue};
			r=m-n;
			if(isNaN(r)){r=tfObjSort.charSorter(m,n)};
			if(r!=0){return r*d[i]}
		}
		return r
	},
	charSorter:function(x,y){
		if(tfObjSort.ignoreCase){x=x.toLowerCase();y=y.toLowerCase()};
		var s=tfObjSort.chars;
		if(!s){return x>y?1:x<y?-1:0};
		x=x.split("");y=y.split("");l=x.length>y.length?y.length:x.length;
		var p=0;
		for(var i=0;i<l;i++){
			p=s.indexOf(x[i])-s.indexOf(y[i]);
			if(p!=0){break};
		};
		if(p==0){p=x.length-y.length};
		return p
	},
	setThings:function(x){
		this.ignoreCase=x.sortIgnoreCase;
		var s=x.sortCharOrder;
		if(!s){this.chars=false;return true};
		if(!s.sort){s=s.split(",")};
		var a="";
		for(var i=1;i<1024;i++){a+=String.fromCharCode(i)};
		for(var i=0;i<s.length;i++){
			z=s[i].split("");
			var m=z[0]; var n=z[1]; var o="";
			if(z[2]=="_"){o=n+m} else {o=m+n};
			a=a.split(m).join("").split(n).join(o);
		};
		this.chars=a
	}
};
tfObjSort.init();



