/* A libary is simple functions for GAIA
 *
 * Depends on: nothing.
 *
 * Provides:
 *
 * gaia.rot13(): rot13 encrpyt/decrypt
 */


if (!window.gaia) 
  gaia = {};

gaia.debug = false;

gaia.log = function ( ) {
  if (window.console && window.console.log)
    //window.console.log.apply(null, arguments);
    //window.console.log.apply(this, arguments);
    window.console.log.apply(window.console, arguments);
};

gaia.debuglog = function ( ) {
  if (gaia.debug)
    gaia.log.apply(null, arguments);
};

gaia.warn = function ( ) {
  if (window.console && window.console.warn)
    window.console.warn.apply(window.console, arguments);
  return null;
};

gaia.error = function ( ) {
  if (window.console && window.console.error)
    window.console.error.apply(window.console, arguments);
  return null;
};

// Deep-clone an array, object or other value
gaia.clone = function(a) {
  if (a === null)
    return null;

  if (a === undefined)
    return undefined;

  var r;
  if (a.constructor == Array) {
    r = new Array;
    for (var i = 0; i < a.length; ++i)
      r[i] = gaia.clone(a[i]);
    return r;
  }    

  if (a.constructor == Object) {
    // plain object
    r = new Object;
    for (var i in a) {
      r[i] = gaia.clone(a[i]);
    }
    return r;
  }

  
  if (a.constructor == Function)
    return a;

  if (typeof a == "string" || typeof a == "number")
    return a;

  // Some other class, use its constructor and hope it clones
  return new a.constructor(a);
};

  
// Return a unique set of elements, where uniqueness means no
// elements are === to each other. An optional sort function may be
// passed, in which case unique is determined by that function.
gaia.unique = function(a, sortFunc) {
  // var r = gaia.clone(a);
  var r = a.concat();
  if (a.constructor == Array) {
    if (sortFunc && sortFunc.constructor == Function)
      r.sort(sortFunc);
    else
      r.sort();

    var i = 1;
    // remove any element identical to the previous one
    while (i < r.length) {
      if (sortFunc && sortFunc.constructor == Function) {
	// use user-defined sort function to test uniqueness
	if (sortFunc(r[i], r[i-1]) == 0)
	  r.splice(i,1);
	else
	  ++i;
      }
      else {
	if (r[i] === r[i-1])
	  r.splice(i,1);
	else
	  ++i;
      }
    }
  }
  return r;
};

gaia.rot13 = function(s) {
  var r = '';
  for (var i = 0; i < s.length; ++i) {
    var n = s.charCodeAt(i);
    if (n >= 65 && n <= 90) {
      r += String.fromCharCode(((n - 65 + 13) % 26) + 65);
    }
    else {
      if (n >= 97 && n <= 122)
	r += String.fromCharCode(((n - 97 + 13) % 26) + 97);
      else
	r += s.charAt(i);
    }
  }
  return r;
};

gaia.arrayIntersect = function (a, b, func) {
  if (a.length == 0 || b.length == 0)
    return false;

  for (var i = 0; i < a.length; ++i) {
    for (var j = 0; j < b.length; ++j) {
      if (func) {
	// use user-supplied comparison function
	if (func(a[i], b[j]))
	  return true;
      }
      else {
	if (a[i] == b[j])
	  return true;
      }
    }
  }
    
  return false;
};

// string should not contain the leading  '?'
gaia.getQueryParameters = function (queryString, obj) {
  var r;
  if (obj && obj.constructor == Object)
    r = gaia.clone(obj);
  else
    r = new Object;

  var qs = queryString;
  if (qs === null || qs === undefined)
    qs = document.location.search;
    
  // Old-style query strings used '&; to separate name value pairs,
  // the new method is to use a semicolon (;). Accept either
  var nameValuePairs = qs.split(/[;&]/);

  for (var i = 0; i < nameValuePairs.length; ++i) {
    // split name/value pairs on '='. This leaves empty strings in
    // the array if '=' is at the start or end of the string (good!)
    var a = nameValuePairs[i].split('=');
    var name = unescape(a[0]);
    var value = unescape(a.slice(1).join('='));
    if (name === "") {
      if (value !== "")
	gaia.log("gaia.getQueryParameters(): No name for query parameter");
    }
    else {
      if (r.hasOwnProperty(name)) {
	if (r[name].constructor == Array) 
	  // already an array, append value to it
	  r[name].push(value);
	else
	  // convert from string to an array, add value to end
	  r[name] = [ r[name], value ];
      }
      else
	r[name] = value;
    }
  }
    
  return r;
};

gaia.createQueryString = function (parameters, sep) {
  if (sep === null || sep === undefined)
    sep = ';';
  var r = new Array;
  for (var name in parameters) {
    var nameEsc = escape(name);
    var value = parameters[name];
    if (value.constructor == Array) 
      for (var i = 0; i < value.length; ++i)
	r.push(nameEsc + '=' + escape(value[i]));
    else
      r.push(nameEsc + '=' + escape(value));
  }
  return r.join(sep);
};

gaia.unwrapCookies = function (packet) {
  if (!packet)
    packet = document.cookie;
   
  var cookies = packet.split('; ');
  var r = new Object;
  for (var i = 0; i < cookies.length; ++i) 
    r = gaia.getQueryParameters(cookies[i], r);
    
  return r;
};
 
gaia.arrayToObject = function (a) {
  var r = new Object;
  for (var i = 0; i < a.length; ++i) 
    r[a[i]] = true;
  return r;
};


gaia.getStyle = function (el, styleProp) {
  var r;
  
  if (el.currentStyle)
    // Non-standard, but getComputedStyle should be considered
    // expensive since it must traverse the entire cascade and build a
    // large CSSStyleDeclaration representing the many style
    // attributes that apply to the element. See "JavaScript: The
    // Definitive Guide", 4th Edition. David Flanagan.
    r = el.currentStyle[styleProp];
  else
    if (window.getComputedStyle)
      r = document.defaultView.getComputedStyle(el, null).getPropertyValue(styleProp);
  
  return r;
};


gaia.getAbsoluteElementOffset = function(elem) {
  var x = elem.offsetLeft;
  var y = elem.offsetTop; 
  var position = gaia.getStyle(elem, 'position');
  var stopOnStatic = (position == "absolute" || position == "relative");
  
  if (position == "fixed") {
    // What to do for this? Probably ignore scroll values
    console.warn("Fix gaia.getAbsoluteElementOffset() for fixed positioning");
    return [elem.x, elem.y];
  }

  if (elem.ownerDocument.defaultView) {
    if (elem.ownerDocument.defaultView.scrollX)
      x -= elem.ownerDocument.defaultView.scrollX;
    if (elem.ownerDocument.defaultView.scrollY)
      y -= elem.ownerDocument.defaultView.scrollY;
  }
  
  for (var parent = elem; (parent != null && parent != window); 
       parent = parent.offsetParent) {
    
    if (stopOnStatic && gaia.getStyle(parent, 'position') == 'static') {
      break;
    }
    else {
      x += parent.offsetLeft - elem.scrollLeft;
      y += parent.offsetTop - elem.scrollTop;
    }
  }
  return [x, y];
};

gaia.isArray = function (a) {
  return a.splice !== void 0;
};
