// This is a general purpose JS lib written by bmuller@butterfat.net.

/********************************************************************************
  Circles using meters for radius size.
  // This assumes that a degree of latitude/longitude==111 km
  // Construct a new point - this will be the center of the circle
  var point = new GPoint(-79.92427110671997, 32.804374029124304);

  // Construct a new GCircle with a GPoint and the radius size in meters
  var c = new GCircle(point,100);

  // Create a new GPolyline using the points array from the GCircle, your favorite color,
  // and the size of the circle line
  var line = new GPolyline(c.points,"#ff0000",4);

  // add the overlay as usual
  map.addOverlay(line);

*****************************************************************************************************/
function GCircle(p,meters) {
  var radius = meters / 111000;
  this.getX = function(degree) { return (radius*Math.sin(degree*Math.PI/180)); };
  this.getY = function(degree) { return (radius*Math.cos(degree*Math.PI/180)); };
  this.points = new Array();
  for(var i=0; i<37; i++) { this.points[i] = new GPoint((p.x+this.getX(i*10)),(p.y+this.getY(i*10))); }
}

/* map should be an element */
function sizeElement(map,x,y) {
  var h, w;
  // IE sucks
  if(map.currentStyle) {
    h = document.documentElement.clientHeight - (y+50);
    w = document.documentElement.clientWidth - x;
    if(x!=null) map.style['width']= w+"px";
    if(y!=null) map.style['height']=h+"px";
  } else {
    h = window.innerHeight - y;
    w = window.innerWidth - x;
    if(x!=null) map.style.width=w+"px";
    if(y!=null) map.style.height=h+"px";
  }
}

function sizeElementFromTop(map, y) {
   // IE sucks
   if(map.currentStyle) {
      var h = document.documentElement.clientHeight - (y+50);
      map.style['top']=h+"px";
   } else {
      var h = window.innerHeight - y;
      map.style.top=h+"px";
   }
}


String.prototype.join = function(a) {
   var result = "";
   var joiner = new String(this);
   for(var i=0; i<a.length; i++) { result+=a[i]+joiner; }
   result = result.substring(0,result.length-joiner.length);
   return result;
}

String.prototype.replace = function(first, second) {
   var s = this.toString().split(first);
   var n = new String(second);
   return n.join(s).toString();

   while((index=s.indexOf(first))!=-1) 
      s=s.substring(0,index)+second+s.substring(index+first.length,s.length);
   return s;
}

String.prototype.maxLength = function(max) {
   var s = this.toString();
   if(s.length > max) return s.substring(0,max);
   return s;
}

Array.prototype.getIndexWithFunction = function(fnc) {
   var thisArray = this;
   for(var i=0; i<thisArray.length; i++) if(fnc(thisArray[i])) return i;
   return -1;
}

Array.prototype.getByIndexFunction = function(fnc) {
   var r = new Array();
   var thisArray = this;
   for(var i=0; i<this.length; i++) if(fnc(i)) r.push(thisArray[i]);
   return r;   
}

Array.prototype.frontPush = function(obj) {
   var thisArray = this;
   var nArray = new Array();
   nArray[0] = obj;
   thisArray.each(function(item) { nArray.push(item); });
   return thisArray;
   //nArray.ceach(function(item, index) { thisArray[index]=item; });
}

Array.prototype.getIndex = function(obj) {
   return this.getIndexWithFunction(function (x) { return x==obj; });
}

Array.prototype.swap = function(indexOne, indexTwo) {
   var thisArray = this;
   var tmp = thisArray[indexOne];
   thisArray[indexOne] = thisArray[indexTwo];
   thisArray[indexTwo] = tmp;
}

Array.prototype.getWithFunction = function(compFnc) {
   var r = new Array();
   var thisArray = this;
   for(var i=0; i<this.length; i++) if(compFnc(thisArray[i])) r.push(thisArray[i]);
   return r;
}

Array.prototype.each = function (func) {
   var thisArray = this;
   for(var i=0; i<thisArray.length; i++) func(thisArray[i]);
}

Array.prototype.ceach = function (func) {
   var thisArray = this;
   for(var i=0; i<thisArray.length; i++) func(thisArray[i], i);
}

Array.prototype.get = function(value) {
   return this.getWithFunction(function(x) { return value==x; });
}

Array.prototype.unshiftArray = function(a) {
   a = a.reverse();
   for(var i=0; i<a.length; i++) this.unshift(a[i]);
}

Array.prototype.includes = function(a) {
   return this.get(a).length > 0; 
}

Array.prototype.cmap = function(func) {
   var thisArray = this;
   var newArray = new Array();
   for(var i=0; i<thisArray.length; i++) newArray.push(func(thisArray[i], i));
   return newArray;
}

function XMLEscapeText(s) {
   if (s == null) return "";
   s = s.replace('&', '&amp;');
   s = s.replace('>', '&gt;');
   s = s.replace('<', '&lt;');
   return s;
}

// This next function is a general function for parsing simple xml docs.
// You pass in a function that describes how to create a new object for each element
// in the request's response xml w/ name of tag.  Returns array of created objects.
function forEachElement(request, tag, fnc) {
   var a = new Array();
   var elems = request.responseXML.documentElement.getElementsByTagName(tag);
   for(var i=0; i<elems.length; i++) {
      var elemObj = {};
      for(var j=0; j<elems[i].attributes.length; j++) {
	 elemObj[elems[i].attributes[j].name]=elems[i].attributes[j].value;
      }
      if(elems[i].firstChild != null && elems[i].firstChild.nodeValue != null) {
         elemObj.inner_text = elems[i].firstChild.nodeValue;
      }
      a.push(fnc(elemObj));
   }
   return a;
}

function forEachJSONElement(request, fnc) {
   var elems = eval(request.responseText);
   return map(fnc, elems);   
}

function rootToObject(request) {
   var elem = request.responseXML.documentElement;
   var elemObj = {};
   for(var j=0; j<elem.attributes.length; j++) {
      elemObj[elem.attributes[j].name]=elem.attributes[j].value;
   }
   return elemObj;
}

function ButterLib() {
   this.current_id = -1;
   this.getID = function() {
      this.current_id++;
      return "BUTTER_ID_"+this.current_id;
   }
   // test for IE
   this.isEvil = function() { return document.documentElement.currentStyle; };
}

/* call remote function fname at location with args - requires Mochikit 
   Probably will want to do a "var callRemoteButter = partial(callRemote, '/ajax.php');" */
function callRemote(location, fname, args) {
   var c = "<function name=\""+fname+"\">";
   for (prop in args)
      c += "<arg name=\"" + prop + "\">" + XMLEscapeText(args[prop]) + "</arg>";
   c = "f=" + urlEncode(c+"</function>");
   return doXHR(location,{method: 'POST',sendContent: c,headers: {"Content-type": "application/x-www-form-urlencoded"}});
}

function cforEach(a, f) {
   for(var i=0; i<a.length; i++) f(a[i], i);
}

function getQueryParam(name) {
   var qstring = window.location.search.substring(1, window.location.search.length);
   var pair = qstring.split('&');
   var values = null;
   var rvalue = null;
   pair.each(function (x) {
		values = x.split('=');
		if(values[0] == name) rvalue = unescape(values[1]);
	     });
   return rvalue;
}

var uncompressPoints = function(a){
   var b=a.length;
   var c=0;
   var d=new Array();
   var e=0;
   var f=0;
   while(c<b) {
      var g;
      var h=0;
      var i=0;
      do {
         g=a.charCodeAt(c++)-63;
         i|=(g&31)<<h;
	 h+=5
      } while(g>=32);
      var l= i&1?~(i>>1):i>>1;
      e+=l;
      h=0;
      i=0;
      do {
         g=a.charCodeAt(c++)-63;
         i|=(g&31)<<h;
	 h+=5
      } while(g>=32);
      var m=i&1?~(i>>1):i>>1;
      f+=m;
      var clean = function(x) { return x.substring(0, x.length-5)+"."+x.substring(x.length-5, x.length); };
      d.push(new GLatLng(clean(""+e), clean(""+f)));
   }
   return d;
}
