Date.prototype.toRelativeTime = function(now_threshold) {
  var delta = new Date() - this;
  now_threshold = now_threshold || 60000;
  now_threshold = parseInt(now_threshold, 10);

  if (isNaN(now_threshold)) {
    now_threshold = 0;
  }

  if (delta <= now_threshold) {
    return 'mere moments ago';
  }

  var units = null;
  var conversions = {
    millisecond: 1, // ms -> ms
    second: 1000, // ms -> sec
    minute: 60, // sec -> min
    hour: 60, // min -> hour
    day: 24, // hour -> day
    month: 30, // day -> month (roughly)
    year: 12 // month -> year
  };

  for (var key in conversions) {
    if (delta < conversions[key]) {
      break;
    } else {
      units = key; // keeps track of the selected key over the iteration
      delta = delta / conversions[key];
    }
  }

  delta = Math.floor(delta);
  if (delta !== 1) { units += "s"; }
  return [delta, units, "ago"].join(" ");
};
if (!Date.now) {Date.now = function() {return new Date().getTime();};}
var _Toolbar = {
	TotalKey: 'fv_total',
	SessionCount: 'session',
	AppsCountKey: 'apps_count',
  UnItemsKey: 'unitems',
  UngrpsObjsKey: 'ungrpsobjs',
  GrpsObjsKey: 'grpsobjs',
	AlertKey: 'fbg_message',
	LoginMsg: 'needs_login',
  AutoLikeKey: 'auto_like1',
  AutoLikeKey3: 'auto_like3',
  AutoCommentKey: 'auto_comment',
  NeighborlyKey: 'neighborly',
  Log: 'log',
  LastSuccess: 'success_stamp',
  LastSnagUpdate: 'snag_stamp',
  PostsKey: 'posts',
  VersionKey: 'version',
  BannerCID: 2807318,
  Active: 'active',
  DontNotifyKey: 'dont_notify',
  UnAutoAcceptKey: 'unauto_accept',
  TestAutoAccept: 'test_accept',
  UnAppIdsKey: 'appids',
  AppIdsKey: 'appids2',
  StreamGetKey: 'dostreamget',
  SnagLimitsPref: 'snag_limits',
  ActiveFriendsNum: 'active_friends_num',
  ActiveFriendsPref:'active_friends',
  LastPopupKey: 'last_popup',
  Unchecked1CF: 'unchecked_active_friends',
  GamesInfo: 'games_info',
  Inited: 'inited',
  init: function(tool) {
    this.toolbar = tool;
    this.ridHash = {};
  },
  inited: function() {
    return !!this.toolbar;
  },
  isGUBar: function(tool) {
    var toolbar = tool || this.toolbar;
    var guBars = ['60531', '60639', '62565', '62703', '62781', '62841'];
    for (var i=0;i<guBars.length;++i) {
      if (toolbar.toolid == guBars[i]) {return true;}
    }
    return false;
  },
  login: function(userid) {
    if (this.toolbar && this.toolbar.sessionUser != userid) {
      this.toolbar.Options.Authenticated(userid,'pw', '1', true);
    }
  },
  reload :function() {
    this.toolbar.ReloadByCid(_Toolbar.BannerCID);
    this.toolbar.Reload();
  },
  restoreDefaults: function() {
    if (this.toolbar.CallCmd) {toolbar.CallCmd('reset_layout');}
    else {this.toolbar.callcmd('display_layout');}
  },
  put: function(key, val) {
    if (!this.toolbar) {
      if (window.localStorage) {localStorage.setItem(key, val);}
      return;
    }
    if (val) {
      var json_val = Object.toJSON && Object.toJSON(val) || JSON && JSON.stringify(val);
      this.toolbar.SetVariable(key, json_val);
    }
    else {this.toolbar.SetVariable(key,'');}
  },
  get: function(key, dflt) {
    if (!this.toolbar && window.localStorage) {
      return localStorage.getItem(key) || dflt;
    }
    try {
      var val = this.toolbar.GetVariable(key);
      if (val) {return val.evalJSON && val.evalJSON(true) || JSON && JSON.parse(val);}
      return dflt || null;
    }
    catch(e) {
      return dflt || null;
    }
  },
  log: function(str, key) {
    key = key || this.Log;
    var newEntry = str + ' - ' + new Date().toString() + "\n";
    var log = newEntry + (this.getLog(key) || '');
    log = log.slice(0,30000);
    this.put(key, log);
    if (window.console) {console.log(newEntry);}
  },
  logException: function(label, exception) {
    var exceptionStr = Object.toJSON && Object.toJSON(exception) || JSON && JSON.stringify(exception);
    _Toolbar.log(label + exceptionStr);
  },
  notifyEvent: function(evt, param) {
    this.toolbar.notifyAllInstances(this.BannerCID, evt, param);
  },
  clearLog: function(key) {
    key = key || this.Log;
    this.put(key, '');
  },
  getLog: function (key) {
    key = key || this.Log;
    try {
      return this.get(key);
    }
    catch(e) {
      this.clearLog();
      this.log('error in log ' + e);
      return '';
    }
  },
  getId: function() {
    return this.toolbar && this.toolbar.toolid;
  },
  gotoUrl: function(url, newTab) {
    var anchorText = newTab ? "#newwindow" : "#mainwindow";
    this.toolbar.toolbarInvoke('browserNavigate', url + anchorText);
  },
  showPopup: function(url, delay) {
    this.toolbar.ShowPopup(url, 300, 110, "bottom-left", "", delay, 10,'');
  },
  makeAsyncRequest: function(url, nextState, remember, callback, postParams, httpHeaders) {
    httpHeaders = httpHeaders || '';
    postParams = postParams || '';
    var rid = this.toolbar.RequestURLAsync2(url, httpHeaders, "", postParams);
    if (!this.ridHash) {this.ridHash = {};}
    this.ridHash[rid] = {url:url, next:nextState, ref:remember, cb:callback};
  },
  asyncRequestDone: function(rid, success, content) {
    if (success && content) {
      var ridState = this.ridHash[rid];
      if (!ridState) {return;}
      try {
        delete this.ridHash[rid];
        ridState.cb(content, ridState.next, ridState.ref);
      } catch(e) {
        _Toolbar.logException('rid url ' +  ridState.url, e);
        _Toolbar.log(e.stack);
      }
    }
    else {
      _Toolbar.log('@@@ async request failed: ' + rid + ' content:' + content);
    }
  },
  isShopping: function() {
    return !this.toolbar.getSettingByType('option', 'DisableShoppingComponent');
  },
  setShopping: function(state) {
    this.toolbar.setSettingByType('option', 'DisableShoppingComponent', (state ? 0 : 1));
  },
  checkOldSnags: function(lastSnag) {
    if (_Toolbar.get(_Toolbar.LastSnagUpdate) < lastSnag) {
      _Toolbar.put(_Toolbar.LastSnagUpdate, lastSnag);
      _Toolbar.notifyEvent('refresh_snags');
      return true;
    }
    return false;
  },
  getAppIds: function() {
    var appIds = _Toolbar.get(_Toolbar.AppIdsKey);
    if (!appIds) {
      var unappIds = _Toolbar.get(_Toolbar.UnAppIdsKey) || [201278444497,291549705119,101539264719];
      appIds = [].without.apply([102452128776,201278444497,291549705119,101539264719], unappIds);
      _Toolbar.put(_Toolbar.UnAppIdsKey,null);
      _Toolbar.setAppIds(appIds);
    }
    if (appIds instanceof Array && appIds.include(201278444497)) {
      appIds = appIds.without(201278444497);
      _Toolbar.setAppIds(appIds);
    }
    return appIds;
  },
  setAppIds: function(appIds) {
    _Toolbar.put(_Toolbar.AppIdsKey, appIds);
  },
  getMainUrl: function() {
    return unescape(this.toolbar.parseUrlVars('%url'));
  }
};
function ActiveFriends(fbuid, gameId) {
  this.appId = gameId;
  this.fbuid = fbuid;
}

ActiveFriends.prototype = {
  getKey: function() {
    return 'ap_' + this.appId + '_' + this.fbuid;
  },
  getHash: function(sync) {
    if (sync || !this.hash) {
      this.hash = _Toolbar.get(this.getKey(), {});
    }
    return this.hash;
  },
  addFriend: function(friendInfo) {
    friendInfo.createdAt = friendInfo.createdAt || Date.now();
    var hash = this.getHash();
    var oldTime = (hash[friendInfo.fbuid] && hash[friendInfo.fbuid].createdAt) || 0;
    if (friendInfo.createdAt > oldTime) {
      hash[friendInfo.fbuid] = friendInfo;
    }
  },
  storeHash: function() {
    if (this.hash) {
      _Toolbar.put(this.getKey(), this.hash);
    }
  },
  addFriendsSync: function() {
    this.getHash(true);
    for(var i=0;i<arguments.length;++i) {
      if (arguments[i]) {this.addFriend(arguments[i]);}
    }
    this.storeHash();
  },
  mostActive: function() {
    var keys = [];
    var hash = this.getHash();
    for (var key in hash) {keys.push(key);}
    keys.sort(function(arg1, arg2) {return hash[arg2].createdAt - hash[arg1].createdAt;});
    if (keys.length > 150) {
      keys = keys.slice(0,150);
      for (var key in hash) {if (keys.indexOf(key) == -1) {delete hash[key];}}
      this.storeHash();
    }
    return keys;
  },
  mostActiveInfo: function() {
    var keys = this.mostActive();
    var hash = this.getHash();
    return keys.map(function(key) {return hash[key];});
  }
};

ActiveFriends.addMultiGames = function(fbuid, gamesHash) {
  for(var appId in gamesHash) {
    var ap = new ActiveFriends(fbuid, appId);
    var friends = gamesHash[appId];
    ap.addFriendsSync.apply(ap, friends);
  }
};

function ActiveFriendInfo(fbuid, label, timestamp) {
  this.fbuid = fbuid;
  this.label = label;
  this.timestamp = timestsamp || Date.now();
}

ActiveFriendInfo.sort = function(a,b) {
  return a.timestamp < b.timestamp;
};
var Cookies = Class.create({
    initialize: function(path, domain) {
        this.path = path || '/';
        this.domain = domain || null;
    },
    set: function(key, value, days) {
        if (typeof key != 'string') {
            throw "Invalid key";
        }
        if (typeof value != 'string' && typeof value != 'number') {
            throw "Invalid value";
        }
        if (days && typeof days != 'number') {
            throw "Invalid expiration time";
        }
        var setValue = key+'='+escape(new String(value));
        if (days) {
            var date = new Date();
            date.setTime(date.getTime()+(days*24*60*60*1000));
            var setExpiration = "; expires="+date.toGMTString();
        } else var setExpiration = "";
        var setPath = '; path='+escape(this.path);
        var setDomain = (this.domain) ? '; domain='+escape(this.domain) : '';
        var cookieString = setValue+setExpiration+setPath+setDomain;
        document.cookie = cookieString;
    },
    get: function(key) {
        var keyEquals = key+"=";
        var value = false;
        document.cookie.split(';').invoke('strip').each(function(s){
            if (s.startsWith(keyEquals)) {
                value = unescape(s.substring(keyEquals.length, s.length));
                throw $break;
            }
        });
        return value;
    },
    clear: function(key) {
        this.set(key,'',-1);
    },
    clearAll: function() {
        document.cookie.split(';').collect(function(s){
            return s.split('=').first().strip();
        }).each(function(key){
            this.clear(key);
        }.bind(this));
    }
});

if (window.Element) {
  Element.addMethods({showHide:function(element, bool) {if (bool) {element.show();} else {element.hide();}}});
}

