
// We fight crime (or bugs, and bad browsers. Browser detection is bad, mmmkay.)

// navigator typeof checks are here to stop non-browser JS engines from complaining.

var isBrowser = (typeof navigator !== 'undefined');
var is_ie =  isBrowser && ( /msie/i.test(navigator.userAgent) && !/opera/i.test(navigator.userAgent) );
var is_ie5 = isBrowser && ( is_ie && /msie 5\.0/i.test(navigator.userAgent) );
var is_ie6 = isBrowser && ( is_ie && /msie 6\.0/i.test(navigator.userAgent) );
var is_ie7 = isBrowser && ( is_ie && /msie 7\.0/i.test(navigator.userAgent) );
var is_ie8 = isBrowser && ( is_ie && /msie 8\.0/i.test(navigator.userAgent) );
var is_opera = isBrowser && (/opera/i.test(navigator.userAgent));
var is_win_opera = isBrowser && (/Windows/i.test(navigator.userAgent));
var is_khtml = isBrowser && (/Konqueror|Safari|KHTML/i.test(navigator.userAgent));
var is_gecko = isBrowser && (/Gecko/i.test(navigator.userAgent));
var is_gecko18 = isBrowser && ( is_gecko && /rv:1.8/i.test(navigator.userAgent) );
var is_gecko19 = isBrowser && ( is_gecko && /rv:1.9/i.test(navigator.userAgent) );
var is_safari = isBrowser && (/Safari/i.test(navigator.userAgent));
var is_safari_2 = is_safari && (/t\/4/i.test(navigator.userAgent));
var is_safari_3 = is_safari && (/t\/5/i.test(navigator.userAgent));
var is_webkit_52 = is_safari && (/t\/5[23]/i.test(navigator.userAgent));
var is_khtml_43 = is_khtml && (/KHTML\/4\.3/i.test(navigator.userAgent));
var is_safari_31 = is_safari && (/Version\/3.[12]/i.test(navigator.userAgent));
var is_safari_4 = is_safari && (/Version\/4/i.test(navigator.userAgent));
is_safari_31 = is_khtml_43 || is_webkit_52 || is_safari_31 || is_safari_4;
var is_chrome = isBrowser && (/Chrome/i.test(navigator.userAgent));
var is_mac = isBrowser && (/Mac/i.test(navigator.userAgent));
var is_iphone = isBrowser && is_safari && (/Mobile/i.test(navigator.userAgent));

//-----------------------------------------------------------------------------
// 
//  Utility functions
//
//-----------------------------------------------------------------------------

// XXX: No way to DontEnum.

function cloneObj(obj)
{
    var c = {};
    for (var i in obj)
    {
        c[i] = obj[i];
    }
    return c;
}

function cloneArr(inArr)
{
    var arr = [];
  
    for (var i = 0; i < inArr.length; i++)
    {
        arr[i] = inArr[i];
    }

    return arr;
}

Array.prototype.spliceAll = function(i)
{
    for (var x in this) {
        if (i == this[x])
            this.splice(x, 1);
    }

    return this;
}

Array.prototype.toHash = function()
{
    var keys = {};
    for (var i = 0; i < this.length; i++)
    {
        keys[this[i]] = true;
    }

    return keys;
}

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

function isHashEmpty(hash)
{
    var empty = true;
    for (var key in hash)
    {
        if (is(hash[key]))
        {
            empty = false;
            break;
        }
    }
    
    return empty;
}

if (isBrowser && !window.XMLHttpRequest)
{
    window.XMLHttpRequest = function()
    {
        var xmlHttp = null;
        var ex;
        try
        {
            xmlHttp = new ActiveXObject("Msxml2.XMLHTTP.4.0");
        }
        catch (ex)
        {
            try
            {
                xmlHttp = new ActiveXObject("MSXML2.XMLHTTP");
            }
            catch (ex)
            {
                try
                {
                    xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
                }
                catch (ex) {}
            }
        }
        return xmlHttp;
    }
}

function Utility()
{

}

Utility.prototype.stopEvent = function(ev)
{
  ev || (ev = window.event);
  if (!ev) {
    return false;
  }

  if (is_ie) {
    ev.cancelBubble = true;
    ev.returnValue = false;
  } else {
    ev.preventDefault();
    ev.stopPropagation();
  }
  return false;
};

Utility.stopPropagation = function(ev) {
  ev || (ev = window.event);
  if (is_ie) {
    ev.cancelBubble = true;
  } else {
    ev.stopPropagation();
  }
  return true;
};

Utility.prototype.escapeText = function(t) {
  t = t.replace(/\</g, '&lt;');
  t = t.replace(/\>/g, '&gt;');
  t = t.replace(/\&/g, '&amp;');
  t = t.replace(/\"/g, '&quot;');
  t = t.replace(/\'/g, '&39#;');
  t = t.replace(/\*/g, '&42#;');
  return t;
}

Utility.prototype.getEventTarget = function(ev)
{
    var targ = null;

    if (ev.target)
    {
        targ = ev.target;
    }
    else if (ev.srcElement)
    {
        targ = ev.srcElement;
    }
    if (targ.nodeType == 3)
    {
         // XXX: Safari is broken.
        targ = targ.parentNode;
    }
    return targ;
};
Utility.getEventTarget = Utility.prototype.getEventTarget;

Utility.prototype.getRandomInt = function(x)
{
    return Math.floor(x*Math.random());
}

Utility.getRandomInt = function(x)
{
    return Math.floor(x*Math.random());
}

Utility.prototype.suffixize = function(iNumber)
{
    var sNumber = ('' + iNumber);
    var iLastDigit = parseInt(sNumber[sNumber.length - 1], 10);

    if (iLastDigit == 1 && iNumber != 11)
    {
        return iNumber + 'st';
    }
    else if (iLastDigit == 2 && iNumber != 12)
    {
        return iNumber + 'nd';
    }
    else if (iLastDigit == 3 && iNumber != 13)
    {
        return iNumber + 'rd';
    }
    else
    {
        return iNumber + 'th';
    }
}

Utility.prototype.pluralize = function(n, t)
{
    if (rtmLanguage == 'en_US')
    {
        if (n == 1)
        {
            return n + ' ' + t;
        }
        else
        {
            return n + ' ' + t + 's';
        }
    }

    return n + ' ' + fmt(t);
}

function el(id)
{
    if (document.getElementById)
    {
        return document.getElementById(id);
    }
    else if (window[id])
    {
        return window[id];
    }
    return null;
}

function quoted(t) {
    return t ? '"' + t + '"' : '""';
}

function padded(value) {
  return (value<10?('0'+value):value.toString());
}

function setCookie(name, value, expires, path, domain, secure) {
  document.cookie= name + "=" + escape(value) +
    ((expires) ? "; expires=" + expires.toGMTString() : "") +
    ((path) ? "; path=" + path : "") +
    ((domain) ? "; domain=" + domain : "") +
    ((secure) ? "; secure" : "");
}

function getCookie(name) {
  var dc = document.cookie;
  var prefix = name + "=";
  var begin = dc.indexOf("; " + prefix);
  if (begin == -1) {
    begin = dc.indexOf(prefix);
    if (begin != 0) return null;
  } else {
    begin += 2;
  }
  var end = document.cookie.indexOf(";", begin);
  if (end == -1) {
    end = dc.length;
  }
  return unescape(dc.substring(begin + prefix.length, end));
}

function deleteCookie(name, path, domain) {
  if (getCookie(name)) {
    document.cookie = name + "=" +
      ((path) ? "; path=" + path : "") +
      ((domain) ? "; domain=" + domain : "") +
      "; expires=Thu, 01-Jan-70 00:00:01 GMT";
 }
}

function extendObject(me, them)
{
    for (var proto in them.prototype)
    {
        me.prototype[proto] = them.prototype[proto];
    }
}

var HAS_STRING_TABLE = (typeof STRING_TABLE !== 'undefined');

function getfmt(s)
{
    return HAS_STRING_TABLE && (s in STRING_TABLE) ? STRING_TABLE[s] : s;
}

function fmt(s, args)
{
    s = HAS_STRING_TABLE && (s in STRING_TABLE) ? STRING_TABLE[s] : s;
    if (args instanceof Array)
    {
        for (var i = 0; i < args.length; i++)
        {
            s = s.replace("%" + (i+1), args[i]);
        }
        return s;
    }
    else
    {
        return s.replace("%1", args);
    }
}

var STRING_TABLE_CACHE = {};
function _T(s, args)
{
    s = HAS_STRING_TABLE && (s in STRING_TABLE) ? STRING_TABLE[s] : s;
    s = s.replace(new RegExp('\{RTM}', 'g'), 'Remember The Milk');
    if (args)
    {
        var re, text;
        for (var arg in args)
        {
            text = args[arg];
            if (typeof(text) === 'string') {
              text = text.replace(/\$/g, '\$\$\$\$');
            }

            if (arg in STRING_TABLE_CACHE) {
              s = s.replace(STRING_TABLE_CACHE[arg], text);
            } else {
              re = new RegExp('\{' + arg + '}', 'g');
              STRING_TABLE_CACHE[arg] = re;
              s = s.replace(re, text);
            }
        }
    }

    return s;
}

function _TF(s, args)
{
    if (!args)
    {
        args = {};
    }

    args['START_BOLD'] = '<b>';
    args['END_BOLD'] = '</b>';
    args['START_ITALIC'] = '<i>';
    args['END_ITALIC'] = '</i>';
    args['START_LINK'] = '<a href=" ">';
    args['END_LINK'] = '</a>';

    if (s instanceof Array)
    {
        var url = s[1];
        var newwindow = s[2];

        var id = '';
        if (is(args['LINK_ID']))
        {
            id = ' id=' + qtd(args['LINK_ID']);
        }

        var onc = '';
        if (is(args['LINK_ONCLICK']))
        {
            onc = ' onclick=' + qtd(args['LINK_ONCLICK']);
        }

        if (newwindow)
        {
            args['START_LINK'] = '<a ' + id + ' ' + onc + ' href=' + qtd(url) +' target="_blank">';
        }
        else
        {
            args['START_LINK'] = '<a ' + id + ' ' + onc + ' href=' + qtd(url) +'>';
        }

        if (is(args['LINK_WRAP']))
        {
            args['START_LINK'] = '<span id=' + qtd(args['LINK_WRAP']) + '>' + args['START_LINK'];
            args['END_LINK'] = args['END_LINK'] + '</span>';
        }

        s = s[0];
    }

    return _T(s, args);
}

function qtd(t) {
    return t ? '"' + t + '"' : '""';
}

function quoteSearchTerm(str)
{
    if (str.charAt(0) !== '"' && str.indexOf(' ') > -1 && str.charAt(str.length-1) !== '"')
    {
        return '"' + str + '"';
    }

    if (str.indexOf('(') > -1 || str.indexOf(')') > -1)
    {
        return '"' + str + '"';
    }

    return str;
}

function debracket(str)
{
    if (str && str.charAt(0) === '(' && str.charAt(str.length-1) == ')')
    {
        return str.substring(1, str.length-1);
    }
    return str;
}

function normalizeSearchEntry(s)
{
    var x = s.split(/[\s;,]+/);
    var len = x.length;
    var output = {};
    var inQuote = false;
    var words;

    for (var i = 0; i < len; i++)
    {
        if (x[i].charAt(0) == '"')
        {
            words = [];

            while (i < len && x[i].charAt(x[i].length-1) !== '"')
            {
                words.push(x[i]);
                i++;
            }

            if (i < len)
            {
                words.push(x[i]);
            }

            output[words.join(' ')] = true;
        }
        else
        {
            output[x[i]] = true;
        }
    }

    var out = [];

    for (var x in output)
    {
        if (x.indexOf('(') > -1 || x.indexOf(')') > -1)
        {
            out.push('"' + x + '"');
        }
        else
        {
            out.push(x);
        }
    }

    return out;
}

function getWindowSize()
{
    var windowWidth, windowHeight;
    if (window.innerWidth)
    {
        windowWidth = window.innerWidth;
        windowHeight = window.innerHeight;
    }
    else if (document.documentElement && document.documentElement.clientWidth)
    {
        windowWidth = document.documentElement.clientWidth;
        windowHeight = document.documentElement.clientHeight;
    }
    else if (document.body)
    {
        windowWidth = document.body.clientWidth;
        windowHeight = document.body.clientHeight;
    }

    return [windowWidth, windowHeight];
}

function EscapeUnicode(s) {
    var out = [], c, y;
    for (var i = 0; i < s.length; i++) {
        c = s.charCodeAt(i);
        y = (Math.floor(c / 16).toString(16) + (c % 16).toString(16)).toString();
        if (y.length == 2) {
          out.push('\\u00' + y);
        } else {
          out.push('\\u' + y);
        }
    }

    return out.join("");
}

(function () {
    if (typeof JSON != 'undefined') {
        Utility.prototype.encodeJavaScript = Utility.toJSON = JSON.stringify;
        return;
    }
    
    var m = {
            '\b': '\\b',
            '\t': '\\t',
            '\n': '\\n',
            '\f': '\\f',
            '\r': '\\r',
            '"' : '\\"',
            '\\': '\\\\'
        },
        s = {
            array: function (x) {
                var a = ['['], b, f, i, l = x.length, v;
                for (i = 0; i < l; i += 1) {
                    v = x[i];
                    f = s[typeof v];
                    if (f) {
                        v = f(v);
                        if (typeof v == 'string') {
                            if (b) {
                                a[a.length] = ',';
                            }
                            a[a.length] = v;
                            b = true;
                        }
                    }
                }
                a[a.length] = ']';
                return a.join('');
            },
            'boolean': function (x) {
                return String(x);
            },
            'null': function (x) {
                return "null";
            },
            number: function (x) {
                return isFinite(x) ? String(x) : 'null';
            },
            object: function (x) {
                if (x) {
                    if (x instanceof Array) {
                        return s.array(x);
                    }
                    var a = ['{'], b, f, i, v;
                    for (i in x) {
                        v = x[i];
                        f = s[typeof v];
                        if (f) {
                            v = f(v);
                            if (typeof v == 'string') {
                                if (b) {
                                    a[a.length] = ',';
                                }
                                a.push(s.string(i), ':', v);
                                b = true;
                            }
                        }
                    }
                    a[a.length] = '}';
                    return a.join('');
                }
                return 'null';
            },
            string: function (x) {
                if (/["\\\x00-\x1f]/.test(x)) {
                    x = x.replace(/([\x00-\x1f\\"])/g, function(a, b) {
                        var c = m[b];
                        if (c) {
                            return c;
                        }
                        c = b.charCodeAt();
                        return '\\u00' +
                            Math.floor(c / 16).toString(16) +
                            (c % 16).toString(16);
                    });
                }
                return '"' + x + '"';
            }
        };

    Utility.toJSON = Utility.prototype.encodeJavaScript = function(arg) {
        var f = s[typeof arg];
        if (f) {
            return f(arg);
        }

        return s.string(String(arg));
    };
})();

Utility.SortAndSign = function(params) {
  var SID = getCookie("SID");
  var params_out = [];

  for (var key in params) {
    params_out.push([key, params[key]]);
  }

  params_out.sort(function(a, b) {
    return (a[0] === b[0]) ? 0 : (a[0] < b[0] ? -1 : 1);
  });

  var to_sign = [], param, q = [];
  for (var i = 0, j = params_out.length; i < j; i++) {
    param = params_out[i];
    to_sign.push(param[0] + param[1]);
    q.push(param[0] + '=' + param[1]);
  }

  if (SID) {
    q.push('sig=' + hex_sha1(SID.substring(0, 40) + to_sign.join('')));
  }

  return q.join('&');
};

Utility.IS_HTTPS = isBrowser && window && 'location' in window && 'protocol' in window.location && window.location.protocol === 'https:';
Utility.getImageUrl = function(url) {
  if (Utility.IS_HTTPS || (HAS_GEARS && window.rtmIsOffline)) {
    return url;
  }

  return 'http://static.rememberthemilk.com' + url;
};

Utility.enableForm = function(e, state) {
  map(function(obj) {
    if (!obj) {
      return;
    }
    obj = (typeof(obj) === 'string' ? el(obj) : obj);

    if (!obj) {
      return;
    }

    var inp = obj.getElementsByTagName('input');
    map(function(i) {
      i.disabled = !state;
      if (state) {
        Utility.removeClass(i, 'disabled');
      } else {
        Utility.addClass(i, 'disabled');
      }
    }, inp);
    var sel = obj.getElementsByTagName('select');
    map(function(i) {
      i.disabled = !state;
      if (state) {
        Utility.removeClass(i, 'disabled');
      } else {
        Utility.addClass(i, 'disabled');
      }
    }, sel);
    var txt = obj.getElementsByTagName('textarea');
    map(function(i) {
      i.disabled = !state;
      if (state) {
        Utility.removeClass(i, 'disabled');
      } else {
        Utility.addClass(i, 'disabled');
      }
    }, txt);
  }, e instanceof Array ? e : [e]);
};

Utility.CLASS_REGEXP_CACHE = {};
Utility.CLASS_REGEXP_REMOVE_CACHE = {};
Utility.hasClass = function(el, className) {
  var re;
  if (className in Utility.CLASS_REGEXP_CACHE) {
    re = Utility.CLASS_REGEXP_CACHE[className];
  } else {
    re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)');
    Utility.CLASS_REGEXP_CACHE[className] = re;
  }
  return re.test(el.className);
};

Utility.addClass = function(el, className) {
  if (Utility.hasClass(el, className)) {
    return false;
  }

  el.className = [el.className, className].join(' ');
};

Utility.removeClass = function(el, className) {
  var re;
  if (className in Utility.CLASS_REGEXP_REMOVE_CACHE) {
    re = Utility.CLASS_REGEXP_REMOVE_CACHE[className];
  } else {
    re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', 'g');
    Utility.CLASS_REGEXP_REMOVE_CACHE[className] = re;
  }

  if (!Utility.hasClass(el, className)) {
    return false;
  }

  var c = el.className;
  el.className = c.replace(re, ' ');
  if (Utility.hasClass(el, className)) {
    Utility.removeClass(el, className);
  }
};

Utility.replaceHTML = function(el, html) {
  if (is_ie) {
    el.innerHTML = html;
    return el;
  }

  var new_el = el.cloneNode(false);
  new_el.innerHTML = html;
  el.parentNode.replaceChild(new_el, el);
  return new_el;
};

function getGeolocationInstance() {
  if (typeof navigator == 'undefined') {
    return null;
  }
  
  if (navigator.geolocation) {
    return navigator.geolocation;
  }
  
  if (typeof google != 'undefined') {
    var geolocation;
    try {
      geolocation = google.gears.factory.create('beta.geolocation');
    } catch (e) {
      geolocation = null;
    }
    
    if (geolocation) {
      navigator.geolocation = geolocation;
      return geolocation;
    }
  }
  
  return null;
}
