var Util = {
	highLight : function(e){
	  $(e).addClassName('highlight');
	},

	unHighLight : function(e){
	  $(e).removeClassName('highlight');
	},

	showWait : function(){
		return '<br><br><div style="clear:both;border:1px solid ##000;margin-right:auto;margin-left:auto;text-align:center;"><div class="wait"></div></div>';
	},
	
	showCMWait : function(){
		return '<div style="margin-right:auto; margin-left:auto; text-align:center;"><div class="cc_wait2"></div></div>';
	},		
    
	showCCWait : function(){
		return '<div style="clear:both;border:1px solid ##000;margin-right:auto;margin-left:auto;text-align:center;"><div class="cc_wait"></div></div>';
	},    

	deleteCookie : function (cname, domain) {
    Util.setCookie(cname, "", domain, -1);
  },
	
  // domain and expiredays are optional.  If expiredays not set, cookie
  // expiration date will be set to a large value (10 year timeout)
  setCookie : function(cname, value, domain, expiredays) {
    // must set cookies in upper case to match coldfusion
    var cnameupper = cname.toUpperCase();

    var exdate = new Date();

    if (value == null) {
      value = '';
      exdate.setDate(exdate.getDate() - 1);
    } else if (expiredays == null) {
      exdate.setFullYear(exdate.getFullYear()+10);
    } else {
      exdate.setDate(exdate.getDate()+expiredays);
    }

    var cookie = cnameupper + "=" + escape(value) + ";";
    cookie = cookie + "expires=" + exdate.toGMTString() + ";";
    cookie = cookie + "path=/;";
    if (domain)
      cookie = cookie + "domain=" + domain + ";"

    document.cookie = cookie;
	},
	
  readCookie : function (name) {
    var cookies = document.cookie.match(new RegExp("\\b" + name + "=(.*?)(;|$)", 'i'));
    if (cookies) {
      return (unescape(cookies[1]));
    } else {
      return null;
    }
  },

  massageCallbacks : function(c) {
    if (c == null) {
      return null;
    } else if(Object.isFunction(c)) {
      return {
          asynchronous : true,
          onSuccess : c
        };
    } else {
      callbacks = {};
      if (c.asynchronous == true || c.asynchronous == null)
        callbacks.asynchronous = true;
      else
        callbacks.asynchronous = false;

      callbacks.onSuccess = Object.isFunction(c.onSuccess) ? c.onSuccess : Prototype.emptyFunction;
      callbacks.onFailure = Object.isFunction(c.onFailure) ? c.onFailure : Prototype.emptyFunction;

      return callbacks;
    }
  },

  // Convenience wrapper for ajax calls to servlets that accepts more varied
  // forms of callback, as well as providing a request abort method.  The abort
  // method does nothing on a completed request.  Target must return JSON
  // response and accept method 'post'.
  servletCall : function(url, params, callbacks) {
    callbacks = Util.massageCallbacks(callbacks)
    var result = null;

    var request = new Ajax.Request(url, {
        method : 'post',
        asynchronous : callbacks != null && callbacks.asynchronous,
        parameters : params,

        onSuccess : function(response) {
          if (callbacks)
            callbacks.onSuccess(response.responseJSON);
          else
            result = response.responseJSON;
        },

        onFailure : function(response) {
          if (callbacks)
            callbacks.onFailure();
        }
    });

    if (!callbacks) {
      return result;
    } else {
      request.abort = function() {
        if (this.transport.readyState != 4) {
          // prevent and state change callbacks from being issued
          this.transport.onreadystatechange = Prototype.emptyFunction;
          // abort the XHR
          this.transport.abort();
          // update the request counter
          Ajax.activeRequestCount--;
        }
      }.bind(request);
      return request;
    }
  },

  arraysAreEqual : function(a, b, typeCoercion) {
    var a = $A(a);
    var b = $A(b);
    if (a.length != b.length) {
      return false;
    } else {
      for (var i = 0; i < a.length; ++i) {
        if (typeCoercion == null || typeCoercion) {
          if (a[i] != b[i])
            return false;
        } else {
          if (a[i] !== b[i])
            return false;
        }
      }
      return true;
    }
  },

  objectsAreEqual : function(a, b, typeCoercion) {
    var a = $H(a);
    var b = $H(b);

    if (a.keys().length != b.keys().length) {
      return false;
    } else {
      var aKeys = a.keys().sort();

      if (!Util.arraysAreEqual(aKeys, b.keys().sort())) {
        return false;
      } else {
        var mismatchFound = false;
        aKeys.each(function(key) {
          if (typeCoercion == null || typeCoercion) {
            if (a.get(key) != b.get(key)) {
              mismatchFound = true;
              throw $break;
            }
          } else {
            if (a.get(key) !== b.get(key)) {
              mismatchFound = true
              throw $break;
            }
          }
        });
        if (mismatchFound)
          return false;
        else
          return true;
      }
    }
  },

  toSet : function(s) {
    var h = new Hash();
    $A(s).each(function(e) {
      h.set(e, null);
    });

    return h.toObject();
  },

  setsAreEqual : function(a, b) {
    return Util.objectsAreEqual(Util.toSet(a), Util.toSet(b));
  },

  // url must have no leading or trailing space
  isValidUrl : function(url) {
    var exp = /^(([\w]+:)?\/\/)?(([\d\w]|%[a-fA-f\d]{2,2})+(:([\d\w]|%[a-fA-f\d]{2,2})+)?@)?([\d\w][-\d\w]{0,253}[\d\w]\.)+[\w]{2,4}(:[\d]+)?(\/([-+_~.\d\w]|%[a-fA-f\d]{2,2})*)*(\?(&?([-+_~.\d\w]|%[a-fA-f\d]{2,2})=?)*)?(#([-+_~.\d\w]|%[a-fA-f\d]{2,2})*)?$/;
    return exp.test(url);
  },

  // email must have no leading or trailing space
  isValidEmail : function(email) { 
    var exp = /^((([a-z]|[0-9]|!|#|$|%|&|'|\*|\+|\-|\/|=|\?|\^|_|`|\{|\||\}|~)+(\.([a-z]|[0-9]|!|#|$|%|&|'|\*|\+|\-|\/|=|\?|\^|_|`|\{|\||\}|~)+)*)@(((((([a-z]|[0-9])([a-z]|[0-9]|\-){0,61})*([a-z]|[0-9])\.))*(([a-z]|[0-9])([a-z]|[0-9]|\-){0,61})*([a-z]|[0-9])\.)[\w]{2,4}|(((([0-9]){1,3}\.){3}([0-9]){1,3}))|(\[((([0-9]){1,3}\.){3}([0-9]){1,3})\])))$/ 
    return exp.test(email.toLowerCase());
  },

  // country can either be 'us', 'ca', or undefined.
  isValidZip : function(zip, country) { 
    if (!country || country.toLowerCase() == 'us') {
      if (/^\d{5}(-\d{4})?$/.test(zip))
        return true;
    } else if (!country || country.toLowerCase() == 'ca') {
      if (/^[ABCEGHJKLMNPRSTVXY][0-9][A-Z] ?[0-9][A-Z][0-9]$/i.test(zip))
        return true;
    }

    return false;
  },

  // Needs to eventually return object containing observers to allow *stopping* mouse over toggle.
  mouseOverStyleToggle : function(element, mouseOutStyle, mouseOverStyle) {
    element = $(element);
		element.observe('mouseover', function() {
        element.removeClassName(mouseOutStyle);
        element.addClassName(mouseOverStyle);
      });
		element.observe('mouseout', function() {
        element.removeClassName(mouseOverStyle);
        element.addClassName(mouseOutStyle);
      });
  },

  // Allows element param to be a list, for the common case of monitoring enter
  // keys on several form fields.
  //
  // Needs to eventually return object containing observer to allow turning
  // off.
  observeReturnKey : function(elements, observer) {
    if (!Object.isArray(elements))
      elements = [elements];
    
    elements.each(function(element) {
      $(element).observe('keypress', function(event) {
          if(event.keyCode == Event.KEY_RETURN) {
            observer(event);
            // stop processing the event
            Event.stop(event);
          }
        });
      });
  },
  
  //Read a page's GET URL variables and return them as an associative array.
  getUrlVars : function(){
	  var vars = [], hash;
	  
	  if(window.location.href.indexOf('?') >= 0){
		  var hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&');
	
		  for(var i = 0; i < hashes.length; i++)
		  {
			  hash = hashes[i].split('=');
			  vars.push(hash[0]);
			  vars[hash[0]] = hash[1];
		  }
	  }

	  return vars;
  },

  padLeft : function(str, totalChars, padWith) {
    str = str.toString();
    if (str.length < totalChars) {
      while (str.length < totalChars) {
        str = padWith + str;
      }
    }
         
    //if padWith was a multiple character string and str was overpadded
    if (str.length > totalChars) {
      str = str.substring((str.length - totalChars));
    }
           
    return str;
  },

  printDollar : function(amt) {
    var costDollars = Math.floor(amt);
    var costCents = Util.padLeft(Math.round((amt - costDollars ) * 100), 2, '0');
    return '$' + costDollars + '.' + costCents;
  },

  viewportWidth : function(f) {
    if (f == undefined)
      f = 1.0;

    return (document.viewport.getWidth() || document.body.offsetWidth) * f;
  },

  windowHeight : function(f) {
    if (f == undefined)
      f = 1.0;

    return (window.innerHeight || document.body.offsetHeight) * f;
  },

  getIframeDocument : function(id) {
    var i = $(id);
    var d = null;
    try {
      if (i.contentDocument) {
          d = i.contentDocument;
      } else if (i.contentWindow) {
          d = i.contentWindow.document;
      } else {
          d = window.frames[id].document;
      }
    } catch(e) {}

    return d;
  },

  getIframeWindow : function(id) {
    var i = $(id);
    try {
      if (i.contentWindow)
        return i.contentWindow;
      else
        return getIframeDocument(i).window;
    } catch(e) {}

    return null;
  },

  getIframeUrl : function(i) {
    var i = $(i);
    try {
      if (i.contentWindow)
        return i.contentWindow.location.href;
      else
        return getIframeDocument(i).location.href;
    } catch(e) {}

    return null;
  },

  redirect : function(url, delay) {
    setTimeout(function() {
        window.location.href = url;
      }, delay);
  },

  generateUUID : function(length) {
    var chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz!=-_@$%";
    var string_length = length || 11;
    var randomstring = '';
    for (var i=0; i<string_length; i++) {
      var rnum = Math.floor(Math.random() * chars.length);
      randomstring += chars.substring(rnum,rnum+1);
    }
    return randomstring;
  },

  getFileExtension : function(file) {
      return (/[.]/.exec(file)) ? /[^.]+$/.exec(file.toLowerCase()) : '';
  },

  // Ascending numerical sort, returns sorted *copy*
  numericSort : function(a, descending) {
    var a = $A(a);
    a.sort(function (a, b) {
        if (descending)
          return b - a;
        else
          return a - b;
      });
    return a;
  }
}

