
  Utility = function()
  {
  }

  Utility.connectOnce = function(src, signal, dst, func) {
    var d;
    if (typeof(func) == 'undefined') {
      func = dst;
    } else {
      func = MochiKit.Base.method(dst, func);
    }
    var wrapper = function() {
     func.apply(this, arguments);
     MochiKit.Signal.disconnect(d);
     }
    d = MochiKit.Signal.connect(src, signal, wrapper);
  }


  Utility.doSimpleXHRPost = function (url, params)
  {
    var preparedParams = {'__commLink' : Utility.serialize(params), '__commToken': "test"};

    //hack:
    arguments[1] = preparedParams;

    var self = MochiKit.Async;
    var req = self.getXMLHttpRequest();

    if (arguments.length > 1)
    {
      var m = MochiKit.Base;
      var qs = m.queryString.apply(null, m.extend(null, arguments, 1));
    }

    req.open("POST", url, true);
    //taken from prototype, pretty much verbatim

    var requestHeaders =
      ['X-Requested-With', 'XMLHttpRequest',
      'X-MochiKit-Version', MochiKit.Async.VERSION,
      'Accept', 'text/javascript, text/html, application/xml, text/xml, ',
      'Content-type', 'application/x-www-form-urlencoded'];

    /* Force "Connection: close" for Mozilla browsers to work around
    * a bug where XMLHttpReqeuest sends an incorrect Content-length
    * header. See Mozilla Bugzilla #246651.
    */

    if (req.overrideMimeType)
    {
      requestHeaders.push('Connection', 'close');
    }

    for (var i = 0; i < requestHeaders.length; i += 2)
    {
      req.setRequestHeader(requestHeaders[i],
      requestHeaders[i+1]);
    }

    /*self.addCallbacks(
      self.handleLogouts
    );
    */

    var defers = self.sendXMLHttpRequest(req, qs);

    var baseDeferred = new MochiKit.Async.Deferred();

    defers.addCallback(MochiKit.Base.partial(this.handleLogouts, baseDeferred));

    //Return an empty Deferred object for handling Map callbacks
    return baseDeferred;
  }

  /* handleLogouts
  * This function is the first callback after Utility processes a doSimpleXHRPost
  * It checks for a loggedout variable and if it finds none, processes the queued callbacks stored in baseDeferred
  * @param baseDeferred - object MochiKit.Async.Deferred() object which holds a list of callback functions
  * @param response - HTTPResponseObject response from getXMLHttpRequest()
  */
  Utility.handleLogouts = function(baseDeferred, response){

      try{



          var responseObj = eval("("+response.responseText+")");

          if(responseObj.loggedout){
              MochiKit.Signal.signal("mapp", "logged_out");
          }
          else {

              //process MAP callbacks
              baseDeferred.callback(response);
              return;
          }

      }

      catch(ex) {

          log("Hmm.. problems");
	  MochiKit.Style.setStyle("mapLoading", {"display": "none"});
      }




  }

  Utility.serialize = function(a, escapeText)
  {
    var i = 0;
    var s = "";

    if(typeof escapeText == "undefined")
    {
      escapeText = true;
    }

    if (typeof(a) == 'object')
    {
      for (var k in a)
      {
        i++;
        s += 's:'+String(k).length+':"'+String(k)+'";'+this.serialize(a[k], escapeText);
      }

      s = "a:"+i+":{"+s+"}";
    }
    else
    {
      var str = String(a);

      if(escapeText === true)
      {
        str = Utility.escapeText(str);
      }

      s += 's:'+String(a).length+':"'+str+'";';
    }

    return s;
  }

  /**
   * Get the next sibling node from node.
   * @param Node node The node to start searching from
   * @return Node The next sibling
   */
  Utility.getNextSiblingNode = function(node)
  {
    var contentNode = node.nextSibling;

    //keep searching until a node type which is a dom node is found
    while (contentNode.nodeType != 1)
    {
      contentNode = contentNode.nextSibling;
    }

    return contentNode;
  }


    Utility.convertSentence = function(str)
    {
      if (str&&str.length>0)
      {
          var convertedStr = str.toLowerCase();
          return convertedStr.substring(0,1).toUpperCase() + convertedStr.substring(1,convertedStr.length);
      }
      return "";
    }

    Utility.currencyFormat = function(val, round, mixed)
    {
        var roundedValue = Math.round(val*Math.pow(10,round))/Math.pow(10,round);
        if (roundedValue!=Math.round(val) && roundedValue.toString().indexOf(".")>-1)
        {
            var roundedStr = roundedValue.toString();
            var trailLength = roundedStr.substring(roundedStr.indexOf(".")+1).length;
            if (trailLength<round)
            {
                for (var i=0; i<(round-trailLength) && i<10; i++)
                {
                    roundedValue+="0";
                }
            }

        }


        var c = mixed.toString().toLowerCase();
        if (c.indexOf("8364")>-1)
        {
            return "\u20AC" + roundedValue;
        }
        else
        {
            if (c=="eur")
                return "\u20AC" + roundedValue;
            else if (c=="usd" || c=="aus")
                return "$" + val;
            else if (c=="gbp")
                return "£" + roundedValue;
        }
        return mixed + roundedValue;
    }

  Utility.printR = function(obj, depth)
  {
    var breakString = '\n';
    var result = '';
    depth = depth ? depth : 0;

    if (obj.constructor)
    {
      for(var k in obj)
      {
        for(var l = 0; l < depth; l++)
        {
          result+=' ';
        }

        if((obj[k]!=null) && (obj[k].constructor == Array|| obj[k].constructor == Object))
        {
          result += k+"=>"+typeof(obj)+"("+breakString+"" + this.printR(obj[k], depth+1)+")"+breakString;
        }
        else
        {
          result += k+"=>"+obj[k]+breakString;
        }
      }
    }
    else
    {
      result = obj + breakString;
    }

    return result;
  }

  /**
   * Sort an assoc array.
   */
  Utility.sortAssocArray = function(arr)
  {
    var keys = [];

    for (var x in arr)
    {
      keys.push(x);
    }

    keys.sort();

    var newList = [];

    for (var i = 0; i < keys.length; i++)
    {
      newList[keys[i]] = arr[keys[i]];
    }

    return newList;
  }

  /**
   * Convert an assoc array to an indexed one
   * @param array assoc The assoc array
   * @return array The indexed array
   */
  Utility.assocToIndexedArray = function(assoc)
  {
    var indexed = [];

    for (var x in assoc)
    {
      indexed.push(assoc[x]);
    }

    return indexed;
  }

  Utility.escapeText = function(str)
  {
    str = str.replace(/\\/g, "\\\\");
    str = str.replace(/"/g, "\\\"");
    //str = str.replace(/'/g, "\\\'");

    return str;
  }

  /**
   * Get the value of a radio group
   */
  Utility.getRadioGroupValue = function(radioGroupName)
  {
    var radioGroup = document.getElementsByName(radioGroupName);
    var value;

    for (var i = 0; i < radioGroup.length; i++)
    {
      if (radioGroup[i].checked)
      {
        value = radioGroup[i].value;
        return value;
      }
    }

    return value;
  }

  //Base64 functions taken from Wiki

  /**
   * Encode data with base 64
   * @param string s
   */
  Utility.base64Encode = function(s)
  {
    var base64chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'.split("");
    // the result/encrypted string, the padding string, and the pad count
    var r = "";
    var p = "";
    var c = s.length % 3;

    // add a right zero pad to make this string a multiple of 3 characters
    if (c > 0)
    {
      for (; c < 3; c++)
      {
        p += '=';
        s += "\0";
      }
    }

    // increment over the length of the string, three characters at a time
    for (c = 0; c < s.length; c += 3)
    {

      // we add newlines after every 76 output characters, according to the MIME specs
      if (c > 0 && (c / 3 * 4) % 76 == 0)
      {
        //r += "\r\n";
      }

      // these three 8-bit (ASCII) characters become one 24-bit number
      var n = (s.charCodeAt(c) << 16) + (s.charCodeAt(c+1) << 8) + s.charCodeAt(c+2);

      // this 24-bit number gets separated into four 6-bit numbers
      n = [(n >>> 18) & 63, (n >>> 12) & 63, (n >>> 6) & 63, n & 63];

      // those four 6-bit numbers are used as indices into the base64 character list
      r += base64chars[n[0]] + base64chars[n[1]] + base64chars[n[2]] + base64chars[n[3]];

      // add the actual padding string, after removing the zero pad
    }

    return r.substring(0, r.length - p.length) + p;
  }

  /**
   * Decode data from base 64
   * @param string s An encoded data
   */
  Utility.base64Decode = function(s)
  {
    var base64chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'.split("");
    var base64inv = {};

    for (var i = 0; i < base64chars.length; i++)
    {
      base64inv[base64chars[i]] = i;
    }

    // replace any incoming padding with a zero pad (the 'A' character is zero)
    var p = (s.charAt(s.length-1) == '=' ? (s.charAt(s.length-2) == '=' ? 'AA' : 'A') : "");
    var r = "";
    s = s.substr(0, s.length - p.length) + p;

    // remove/ignore any characters not in the base64 characters list -- particularly newlines
    s = s.replace(new RegExp('[^'+base64chars.join("")+']', 'g'), "");

    // increment over the length of this encrypted string, four characters at a time
    for (var c = 0; c < s.length; c += 4)
    {
      // each of these four characters represents a 6-bit index in the base64 characters list
      //  which, when concatenated, will give the 24-bit number for the original 3 characters
      var n = (base64inv[s.charAt(c)] << 18) + base64inv[s.charAt(c+3)] +
      (base64inv[s.charAt(c+1)] << 12) + (base64inv[s.charAt(c+2)] << 6);

      // split the 24-bit number into the original three 8-bit (ASCII) characters
      r += String.fromCharCode((n >>> 16) & 255, (n >>> 8) & 255, n & 255);

      // remove any zero pad that was added to make this a multiple of 24 bits
    }

    return r.substring(0, r.length - p.length);
  }

  Utility.readCookie = function(name)
  {
    var nameEQ = name + "=";
    var ca = document.cookie.split(';');

    for(var i=0;i < ca.length;i++)
    {
      var c = ca[i];

      while (c.charAt(0)==' ')
      {
        c = c.substring(1,c.length);
      }

      if (c.indexOf(nameEQ) == 0)
      {
        return c.substring(nameEQ.length,c.length);
      }
    }

    return null;
  }

