// ==UserScript==
// @name           Facebook Packrat Autoclicker
// @namespace      http://userscripts.org/users/49912
// @description    Clicks automatically on any credit found.
// @source         http://userscripts.org/scripts/show/25856
// @identifier     http://userscripts.org/scripts/source/25856.user.js
// @version        0.10.5
// @date           2008-08-01
// @creator        Piotr P. Karwasz
// @include        http://apps.facebook.com/packrat/*
// @include        http://apps.new.facebook.com/packrat/*
// ==/UserScript==
/* $Revision: 121 $ */
var try_again = document.getElementById('try_again_button');
if (try_again) {
 setTimeout(function(){try_again.click();},3000);
}
/* Update */
var version_timestamp = 1217589537002;
/***
 * Function: Script Update Checker
 *
 * Description:
 * Script Update Checker (http://userscripts.org/scripts/show/20145)
 * written by Jarett (http://userscripts.org/users/38602).
 */
var version_scriptNum = 25856;
function updateCheck(forced){if((forced)||(parseInt(GM_getValue("lastUpdate","0"))+86400000<=(new Date().getTime()))){try{GM_xmlhttpRequest({method:"GET",url:"http://userscripts.org/scripts/review/"+version_scriptNum+"?"+new Date().getTime(),headers:{'Cache-Control':'no-cache'},onload:function(xhrResponse){GM_setValue("lastUpdate",new Date().getTime()+"");var rt=xhrResponse.responseText.replace(/&nbsp;?/gm," ").replace(/<li>/gm,"\n").replace(/<[^>]*>/gm,"");var scriptName=(/@name\s*(.*?)\s*$/m.exec(rt))[1];GM_setValue("targetScriptName",scriptName);if(parseInt(/version_timestamp\s*=\s*([0-9]+)/.exec(rt)[1])>version_timestamp){if(confirm("There is an update available for the Greasemonkey script \""+scriptName+".\"\nWould you like to go to the install page now?")){GM_openInTab("http://userscripts.org/scripts/show/"+version_scriptNum);}}else if(forced){alert("No update is available for \""+scriptName+".\"");}}});}catch(err){if(forced){alert("An error occurred while checking for updates:\n"+err);}}}}GM_registerMenuCommand(GM_getValue("targetScriptName","???")+" - Manual Update Check",function(){updateCheck(true);});updateCheck(false);
/* Basic classes */





var Page = new Object();

Page.init = function() {
  /* Now */
  Page.now = Math.floor(new Date().getTime() / 1000);
  var url = location.href;
  /* New Facebook layout */
  if (url.indexOf('apps.new.facebook.com') != -1) Page.fnew = true;
  else Page.fnew = false;
  /* user */
  var div;
  if (Page.fnew) {
    div = document.getElementById('fb_menu_profile');
  } else {
    div = document.getElementById('navigator');
  }
  div = div.getElementsByTagName('a')[0];
  Page.c_user = div.href.match(/id=([0-9]+)/)[1];
  /* Cut out the params */
  var params = url.split('?');
  if (params[1]) {
    url = params[0];
    params = params[1];
  } else params = undefined;
  var parts = url.split('/');
  /* type */
  Page.c_page = parts[4];
  /* Argument (like user id, etc.) */
  if (parts[5]) Page.c_arg = parts[5]; else Page.c_arg = '';
  /* params */
  Page.c_params = new Object();
  if (!params) return;
  parts = params.split('&');
  for (var i = 0; i < parts.length; i++) {
    var param = parts[i].split('=');
    Page.c_params[param[0]] = param[1];
  }
}

Page.init();
/* vim:set tw=80 sts=2 et ft=javascript: */




/***
 * Object: Utils
 *
 * Description: contains some utilities functions.
 */
Utils = new Object();

/***
 * Method: Element.getElementsByClassName(name, node)
 *
 * Description:
 * Gets a list of elements with a give className.
 *
 * @param name        -- the classname to look for.
 * @param node        -- node on which we start the search.
 * @return array      -- an array of nodes matching the classname.
 */
if (document.getElementsByClassName) {
  /* Firefox 3: native implementation */
  Utils.getElementsByClassName = function(classname, node) {
    if (!node) node = document;
    return node.getElementsByClassName(classname);
  }
} else {
  Utils.getElementsByClassName = function(classname, node) {
    if (!node) node = document;
    var xpathExpression;
    var returnElements = new Array();
    xpathExpression = ".//*[contains(concat(' ', @class, ' '), ' " + classname + " ')]";
    var xpathResult = document.evaluate(xpathExpression, node, null, XPathResult.ANY_TYPE, null);

    while (node = xpathResult.iterateNext()) {
      returnElements.push(node);
    }
    return returnElements;
  }
}

/***
 * Function: Utils.getElementsByXPath(expression, node)
 *
 * Description:
 * Returns an array of elements obtained from evaluating the XPath expression on
 * the node.
 *
 * @param expression         -- the expression to evaluate.
 * @param node               -- context node, defaults to document.
 * @return array             -- an array of elements matching the expression
 */
Utils.getElementsByXPath = function(expression, node) {
  if (!node) node = document;
  var result = new Array();
  var xpathResult;
  xpathResult = document.evaluate(expression, node, null, XPathResult.ORDERED_NODE_ITERATOR_TYPE, null);

  var node;
  while (node = xpathResult.iterateNext()) {
    result.push(node);
  }

  return result;
}
/* vim:set tw=80 sts=2 et ft=javascript: */
function Card(id) {
  this.id = id;
  this.name = 'unknown';
  this.collection = 'unknown';
  this.points = 0;
}

Card.prototype = new Object();

Card.prototype.steal = function() {
}

function CardCollection() {
  this.cards = new Array();
  if (Page.c_page == 'friends' || Page.c_page == 'feats') return;
  var divs = Utils.getElementsByClassName('card-wrapper');
  for (var i = 0; i < divs.length; i++) {
    var front = Utils.getElementsByClassName('front', divs[i])[0];
    if (!front) continue;
    var id = front.id.match(/app2431403991_card_([^_]+)_front/);
    if (id) id = id[1];
    var card = new Card(id);
    var tmp;
    /* Name */
    try {
      tmp = Utils.getElementsByClassName('item', front)[0];
      tmp = tmp.getAttribute('style');
      tmp = tmp.match(/kinds\/([^_]+)(_medium)?(_[0-9a-f]+)?\.gif/);
      if (tmp) card.name = tmp[1];
    } catch(ex) {dump(ex);}
    /* Collection */
    try {
      tmp = Utils.getElementsByClassName('collection-icon', front)[0];
      tmp = tmp.getAttribute('src');
      tmp = tmp.match(/families\/([^_]+)_family_small\.gif/);
      if (tmp) card.collection = tmp[1];
    } catch(ex) {dump(ex);}
    /* Points */
    try {
      tmp = Utils.getElementsByClassName('points', front)[0];
      if (tmp) card.points = parseInt(tmp.innerHTML);
    } catch(ex) {dump(ex);}
    if (Page.c_page == 'market') {
    /* Buy link */
      var slot = Utils.getElementsByXPath('.//span[@class="slot_text"]/a', divs[i])[0];
      if (slot) {
        slot = slot.getAttribute('onclick');
        slot = slot.match(/(\/packrat\/purchase[^']*)'/);
        if (slot) card.purchase = slot[1];
      }
    }
    card.wrapper = divs[i];
    this.cards.push(card);
  }
}

function Collection(slug) {
  this.slug = slug;
  this.name = 'unknown';
  this.expiration = 0;
  this.size = 0;
}

function CollectionData() {
  obj = eval(GM_getValue('collections', '({})'));
  for (var i in obj) {
    this[i] = obj[i];
  }
}

CollectionData.prototype = new Object();

CollectionData.prototype.save = function() {
  GM_setValue('collections', this.toSource());
}

CollectionData.prototype.updateData = function() {
  if (Page.c_page == 'markets' && Page.c_arg == 'onsale') {
    var divs = Utils.getElementsByClassName('minicard');
    for (var i = 0; i < divs.length; i++) {
      var tmp;
      tmp = divs[i].getElementsByTagName('img')[0];
      if (!tmp) continue;
      var slug = tmp.getAttribute('src');
      slug = slug.match(/families\/([0-9a-z\-]+)_family_small\.gif/);
      if (!slug) continue;
      var slug = slug[1];
      var col = new Collection(slug);
      col.name = tmp.alt;
      /* Number of cards */
      tmp = Utils.getElementsByClassName('details', divs[i])[0];
      tmp = tmp.innerHTML.match(/([0-9]+) Cards/);
      if (!tmp) continue;
      col.size = parseInt(tmp[1]);
      /* Expiration */
      tmp = Utils.getElementsByClassName('bl', divs[i])[0];
      tmp = tmp.innerHTML.match(/Expired on (.*)(st|nd|th)(.*)\&nbsp;/);
      if (tmp) {
        var time = new Date(tmp[1] + tmp[3]);
        col.expiration = Math.floor(time.getTime() / 1000);
      }
      this[slug] = col;
    }
    this.save();
  }
}

var pagecards = new CardCollection();
var collections = new CollectionData();
collections.updateData();
/* vim:set tw=80 sts=2 et ft=javascript: */


function Profile() {
  this.credits = 0;
  this.level = 0;
  this.score = 0;
  this.pack = new Object();
  this.vault = new Object();
  this.complete_col = new Array();
  this.preferences = new Object();
  this.vars = new Object();
  var obj = eval(GM_getValue('profile', '({})'));
  for (var i in obj) {
    this[i] = obj[i];
  }
}

Profile.prototype = new Object();

Profile.prototype.save = function() {
  GM_setValue('profile', this.toSource());
}

Profile.prototype.updateData = function() {
  var header = document.getElementById('app2431403991_afire-scoreboard');
  /* Credits */
  var div = Utils.getElementsByClassName('credits', header)[0];
  div = div.innerHTML.replace(/,/g,'');
  this.credits = parseInt(div);
  /* Level */
  div = Utils.getElementsByClassName('level', header)[0];
  div = div.innerHTML;
  this.level = parseInt(div);
  /* Score */
  div = Utils.getElementsByClassName('score', header)[0];
  div = div.innerHTML.replace(/,/g,'');
  this.score = parseInt(div);
  switch (Page.c_page) {
    case '':
      /* Delete old cards */
      for (var i in this.pack) {
        var front = document.getElementById('app2431403991_card_' + i + '_front')
        if (!front) delete this.pack[i];
      }
      /* Retrieve new cards */
      for (var i = 0; i < pagecards.cards.length; i++) {
        var card = pagecards.cards[i];
        if (!card.id) continue;
        delete card.wrapper;
        this.pack[card.id] = card;
      }
      break;
    case 'vault':
      for (var i = 0; i < pagecards.cards.length; i++) {
        var card = pagecards.cards[i];
        if (!card.id) continue;
        if (!this.vault[card.collection]) this.vault[card.collection] = new Array();
        if (this.vault[card.collection].indexOf(card.name) == -1) {
          this.vault[card.collection].push(card.name);
        }
      }
      for (var i in collections) {
        if (!this.vault[i]) continue;
        if (this.vault[i].length == collections[i].size) {
          if (this.complete_col.indexOf(i) == -1) this.complete_col.push(i);
        }
      }
      break;
    default:
      break;
  }
  /* Retrieve the card names in the pack */
  this.pack_ids = new Array();
  for (var i in this.pack) {
    if (this.pack_ids.indexOf(this.pack[i].name) == -1) this.pack_ids.push(this.pack[i].name);
  }
  this.save();
}

/* vim:set tw=80 sts=2 et ft=javascript: */





var Menu = new Object();

Menu.init = function() {
  var menuCode = new Array();
  menuCode.push('<div class="scriptStatusHeader">-Script status-</div>');
  menuCode.push('<div class="scriptStatusContent"><span id="scripterror"></span><a id="scriptresume"></a>Status:<br /><span id="scriptstatus">Resting...</span><br /><span id="scripttimer"></span></div><hr/>');
  menuCode.push('<div class="scriptStatusContent"><p>Notes:</p><ul id="scriptnotes"></ul></div><hr/>');
  menuCode.push('<div><button type="button" id="prefs_button">Script Preferences</button></div>');

  var menu = document.createElement('div');
  menu.id = 'ScriptStatus';
  menu.innerHTML = menuCode.join('\n');
  menuCode.length = 0;

  menuCode.push("#ScriptStatus { z-index: 10; position:fixed; bottom:27px; ");
  if (Page.fnew) {
    menuCode.push("right:2px; ");
  } else {
    menuCode.push("left:2px; ");
  }
  menuCode.push("border:2px solid #6D84B4; background-color:#EEEEEE; color:#3B5998; padding:2px; font-weight:bold; width: 200px; min-height: 100px;}");
  menuCode.push("#ScriptStatus div.scriptStatusHeader { text-align:center; background: #6D84B4; color: #FFFFFF; }");
  menuCode.push("#ScriptStatus div.scriptStatusContent { border-width: 1px 1px 1px 1px; padding: 2px 2px 2px 2px; border-style: solid solid solid solid;}");

  var style = document.createElement('style');
  style.type = 'text/css';
  style.innerHTML = menuCode.join('');

  try { document.getElementsByTagName('head')[0].appendChild(style); }
  catch(e) {}
  document.body.insertBefore(menu, document.body.lastChild);

  var button = document.getElementById('prefs_button');
  button.addEventListener('click', Preferences.show(), true);
}

/* vim:set tw=80 sts=2 et ft=javascript: */



Preferences = new Object();

Preferences.init = function() {
  /* The handlers for preferences */
  this.handlers = new Array();
  this.div = document.createElement('div');
  this.div.className = 'facebook-gm-pref';
  var css = ".facebook-gm-pref {display: none; position: absolute; z-index: 99; left: 200px; top: 200px; overflow: visible; background-color: white; border: 1px solid black; padding: 10px; min-width: 400px; min-height: 400px}";
  GM_addStyle(css);

  /* Setting title */
  this.div.innerHTML = '<h2>Script Preferences</h2>';

  /* Rule */
  this.rule = document.createElement('hr');
  this.rule.id = 'facebook-gm-rule';
  this.div.appendChild(this.rule);

  /* Building form */
  this.form = document.createElement('form');
  this.form.action = '';
  this.form.method = '';
  this.form.id = 'facebook-gm-pref';
  this.div.appendChild(this.form);

  /* Submit button */
  this.button = document.createElement('button');
  this.button.type = 'button';
  this.button.id = 'pref_submit';
  this.button.innerHTML = "Update preferences";
  this.form.appendChild(this.button);
  document.getElementsByTagName('body')[0].appendChild(this.div);
}

Preferences.populate = function(obj) {
  /* Preferences display */
  for (var i = 0; i < modules.length; i++) {
    if (obj[modules[i] + '_preferencesInterface']) {
      obj[modules[i] + '_preferencesInterface'](this);
      var br = document.createElement('br');
      this.form.insertBefore(br, this.button);
    }
  }
  /* Preferences handlers */
  for (var i = 0; i < modules.length; i++) {
    if (obj[modules[i] + '_preferencesHandler']) this.handlers.push(obj[modules[i] + '_preferencesHandler']);
  }
  /* Add event listener */
  this.button.addEventListener('click', this.eventListener(), true);
  this.form.addEventListener('submit', this.eventListener(), true);
}

Preferences.eventListener = function() {
  var prefs = this;
  return function(ev) {
    var reload = false;
    var profile = eval(GM_getValue('profile', '({})'));
    /* Prevent submitting the form to the server */
    ev.preventDefault();
    /* Execute all handlers */
    for (var i = 0; i < prefs.handlers.length; i++) {
      if (prefs.handlers[i](prefs.form, profile)) reload = true;
    }
    prefs.div.style.display = 'none';
    GM_setValue('profile', profile.toSource());
    if (reload) location.reload();
  }
}

Preferences.show = function() {
  var div = this.div;
  return function() {
    div.style.display = 'block';
    div.scrollIntoView(false);
  }
};

Preferences.addToggleBox = function(message, id, value) {
  var option = new Array();
  option.push('<label for="' + id + '">' + message + ":&nbsp;</label>");
  if (value) {
    option.push('Yes <input type="radio" value="true" checked="checked" name="' + id + '"/>');
    option.push('&nbsp;No <input type="radio" value="false" name="' + id + '"/>');
  } else {
    option.push('Yes <input type="radio" value="true" name="' + id + '"/>');
    option.push('&nbsp;No <input type="radio" value="false" checked="checked" name="' + id + '"/>');
  }
  return option.join("\n");
};

Preferences.init();
/* vim:set tw=80 sts=2 et ft=javascript: */


function Timer(min, max) {
  if (min == undefined) min = profile.preferences.timer_min;
  if (max == undefined) max = profile.preferences.timer_max;
  this.priority = 10;
  /* Possible values 'sendevent', 'submitform', 'gotourl' */
  this.type = 'sendevent';
  this.delay = min + Math.floor((max - min) * Math.random());
  this.message = 'Resting...';
}

Timer.queue = new Array();
Timer._delay = 0;
Timer.prototype = new Object();

Timer.prototype.append = function() {
  var types = ['sendevent', 'submitform', 'gotourl'];
  if (types.indexOf(this.type) == -1) throw new TypeError;
  /* Push the timeout on the queue */
  Timer.queue.push(this);
}

Timer.start = function(obj) {
  obj = obj || this;
  var action;
  /* Exit if we have nothing to do */
  if (!obj.queue.length) return;
  idx = 0;
  var priority = obj.queue[0].priority;
  var action = obj.queue[0];
  var delay = Infinity;
  /* Select the action */
  for (i = 1; i < obj.queue.length; i++) {
    if (obj.queue[i].priority < priority ||
        (obj.queue[i].priority == priority && obj.queue[i].delay < delay)) {
        priority = obj.queue[i].priority;
        delay = obj.queue[i].delay;
        action = obj.queue[i];
        idx = i;
    }
  }
  action.delay -= obj._delay;
  /* Message */
  var span = document.getElementById('scriptstatus');
  span.innerHTML = action.message;
  /* Delay */
  span = document.getElementById('scripttimer');
  var sec = Math.ceil(action.delay / 1000);
  if (sec) {
    var str = (sec % 60) + ' s';
    sec = Math.floor(sec / 60);
    if (sec) {
      str = (sec % 60) + ' m ' + str;
      sec = Math.floor(sec / 60);
      if (sec) str = sec + ' h ' + str;
    }
    span.innerHTML = 'in ' + str;
  } else span.innerHTML = '';

  if (action.delay <= 0) switch(action.type) {
    case 'sendevent':
      obj.queue.splice(idx, 1);
      action.target.dispatchEvent(action.event);
      break;
    case 'gotourl':
      /* Other events are ignored */
     location.href = action.url;
      obj.queue = new Array();
      break;
    case 'submitform':
      obj.queue = new Array();
      action.form.submit();
      break;
    default:
      alert("Unknown action type: " + action.type);
      break;
  };
  obj._delay = Math.min(action.delay, 500);
  /* Execute us again if we have other actions */
  if (obj.queue.length) obj.timer = setTimeout(obj.start, obj._delay, obj);
}

function timer_preferencesInterface(prefs) {
  if (profile.preferences.timer_min == undefined) profile.preferences.timer_min = 500;
  if (profile.preferences.timer_max == undefined) profile.preferences.timer_max = 1500;
  var option = new Array();
  var value = profile.preferences.timer_min;
  option.push('<h2>Timer preferences</h2><br/>');
  option.push('<label>Delay actions from <input type="text" name="timer_min" maxlength="5" size="5" value="' + value + '"/> ms</label> <label>to ');
  value = profile.preferences.timer_max;
  option.push('<input type="text" name="timer_max" maxlength="5" size="5" value="' + value + '"/> ms.</label>');
  var div = document.createElement('div');
  div.innerHTML = option.join("\n");
  prefs.form.insertBefore(div, prefs.button);
}

function timer_preferencesHandler(form, profile) {
  var ret = false;
  var prefs = profile.preferences;
  var input = form.elements.namedItem('timer_min');
  input = parseInt(input.value);
  if (prefs.timer_min != input) {
    prefs.timer_min = input;
    ret = true;
  }

  input = form.elements.namedItem('timer_max');
  input = parseInt(input.value);
  if (prefs.timer_max != input) {
    prefs.timer_max = input;
    ret = true;
  }

  return ret;
}
/* vim:set tw=80 sts=2 et ft=javascript: */

/* Modules */
var modules = ['timer', 'credit', 'popup', 'collection', 'highlight', 'grinding', 'browse'];




var CREDIT_MAX = 1000;

function credit_exec() {
  if (profile.vars.credit_amount == undefined) profile.vars.credit_amount = 0;
  if (profile.preferences.credit_enabled) {
    if (!profile.vars.credit_amount) {
      var idx = profile.vars.browse_module.indexOf('credit');
      if (idx + 1) profile.vars.browse_module.splice(idx, 1);
    }
    var credit = Utils.getElementsByClassName('free-credits-amount');
    for (var i = 0; i < credit.length; i++) {
      profile.vars.credit_amount -= parseInt(credit[i].innerHTML);
      var timer = new Timer();
      timer.message = "Collecting credits";
      timer.priority = -1;
      timer.target = credit[i].parentNode;
      var evt = document.createEvent('MouseEvent');
      evt.initEvent('mousedown', true, true);
      timer.event = evt;
      timer.append();
    }
  }
}

function credit_preferencesInterface(prefs) {
  if (profile.preferences.credit_enabled == undefined) profile.preferences.credit_enabled = false;
  var value = profile.preferences.credit_enabled;
  var option = new Array();
  option.push('<h2>Free credits</h2><hr/>');
  option.push('<label for="credit_enabled">Collect credits automatically:</label>');
  if (value) {
    option.push('Yes <input type="radio" name="credit_enabled" value="1" checked="checked"/>');
    option.push('No <input type="radio" name="credit_enabled" value="0"/>');
  } else {
    option.push('Yes <input type="radio" name="credit_enabled" value="1"/>');
    option.push('No <input type="radio" name="credit_enabled" value="0" checked="checked"/>');
  }
  var div = document.createElement('div');
  div.innerHTML = option.join('\n');
  prefs.form.insertBefore(div, prefs.button);
  option = new Array();
  option.push('<label for="credit_amount">Gather <input name="credit_amount" type="text" size="4" maxlength="4" ');
  if (profile.vars.credit_amount < 0) profile.vars.credit_amount = 0;
  option.push('value="' + profile.vars.credit_amount + '"/> credits.</label>');
  option.push('<br/>');
  div = document.createElement('div');
  div.innerHTML = option.join('\n');
  prefs.form.insertBefore(div, prefs.button);
}

function credit_preferencesHandler(form, profile) {
  var ret = false;
  var input = form.elements.namedItem('credit_enabled');
  if (profile.preferences.credit_enabled != input.checked) {
    profile.preferences.credit_enabled = input.checked;
    ret = true;
  }
  input = form.elements.namedItem('credit_amount');
  input = parseInt(input.value);
  if (profile.vars.credit_amount != input) {
    profile.vars.credit_amount = input;
    ret = true;
  }
  var idx;
  if (profile.preferences.credit_enabled) {
    if (profile.vars.credit_amount
         && (idx = profile.vars.browse_module.indexOf('credit')) == -1) {
      profile.vars.browse_module.push('credit');
    } else if (!profile.vars.credit_amount
                && (idx = profile.vars.browse_module.indexOf('credit')) != -1) {
      profile.vars.browse_module.splice(idx, 1);
    }
  } else if ((idx = profile.vars.browse_module.indexOf('credit')) != -1) {
    profile.vars.browse_module.splice(idx, 1);
  }
  return ret;
}
/* vim:set tw=80 sts=2 et ft=javascript: */





function popup_exec() {
  var elms = Utils.getElementsByClassName('grab-item');
  var pause = browse_pause(false);

  for (var i = 0; i < elms.length; i++) {
    /* Just the name and colletion of the card */
    /* Collection */
    var col = Utils.getElementsByClassName('collection-badge', elms[i])[0];
    if (!col) col = Utils.getElementsByClassName('collection-icon', elms[i])[0];
    col = col.getAttribute('src');
    col = col.match(/families\/([0-9a-z\-]+)_family_small\.gif/);
    col = col[1];
    /* Name */
    var name = Utils.getElementsByClassName('item', elms[i])[0];
    name = name.getAttribute('style');
    name = name.match(/kinds\/([0-9a-z\-]+)(_medium)?(_[0-9a-f]+)?\.gif/);
    name = name[1];
    var stat = eval(GM_getValue('popstat', '([])'));
    stat.push(col + "/" + name);
    GM_setValue('popstat', stat.toSource());
    /* Action */
    var ac = Utils.getElementsByXPath('.//div[@class="action"]//a', elms[i])[0];

    switch (profile.preferences.popup_behaviour) {
      case 'ignore':
        return;
      case 'pause':
        pause();
        return;
      case 'work':
        if (profile.preferences.collection_work.indexOf(col) == -1) return;
        break;
      default:
        break;
    }
    var action = new Timer();
    action.message = "Collecting popup...";
    action.priority = -1;
    action.target = ac;
    var evt = document.createEvent('MouseEvent');
    evt.initEvent('mousedown', true, true);
    action.event = evt;
    action.append();
  }
}

function popup_preferencesInterface(prefs) {
  if (profile.preferences.popup_behaviour == undefined) profile.preferences.popup_behaviour = 'pause';
  var value = profile.preferences.popup_behaviour;
  var option = new Array();
  option.push('<h2>Popups</h2><hr/>');
  option.push('<label for="popup_behaviour">Popup behaviour</label><br/>');
  var types = {pause:'Pause browsing cycle', ignore:'Ignore all', work:'Pickup from selected collections only', all:'Pickup all'};
  for (var i in types) {
    option.push('<input type="radio" name="popup_behaviour" ');
    option.push('value="' + i + '"');
    if (value == i) option.push(' checked="checked"');
    option.push('>' + types[i] + '</input>');
  }
  option.push('<br/>');
  var div = document.createElement('div');
  div.innerHTML = option.join('');
  prefs.form.insertBefore(div, prefs.button);
}

function popup_preferencesHandler(form, profile) {
  var value = profile.preferences.popup_behaviour;
  for (var i = 0; i < form.elements.length; i++) {
    var el = form.elements[i];
    if (el.name != 'popup_behaviour') continue;
    if (el.checked) break;
  }

  if (el.value != value) {
    profile.preferences.popup_behaviour = el.value;
    return true;
  } else return false;
}
/* vim:set tw=80 sts=2 et ft=javascript: */





function collection_exec() {
  if (profile.vars.collection_check == undefined) profile.vars.collection_check = 0;
  if (profile.vars.collection_vault == undefined) profile.vars.collection_vault = 0;
  /* Update collections list */
  if (Page.c_page == 'markets' && Page.c_arg == 'onsale') {
    collections.updateData();
    profile.vars.collection_check = Page.now + 7 * 86400;
  }
  /* Check new collections */
  if (profile.vars.collection_check < Page.now) {
    var action = new Timer();
    action.priority = 0;
    action.message = 'Checking available collections...';
    action.type = 'gotourl';
    action.url = 'http://apps.facebook.com/packrat/markets/onsale';
    action.append();
    return;
  }
  /* Checking vaulted cards */
  if (Page.c_page == 'vault' && Page.c_arg == '') {
    var div = Utils.getElementsByXPath('//ul[@class="paging"]//a');
    div = div[div.length-1];
    if (div.innerHTML != 'Next') profile.vars.collection_vault = Page.now + 7 * 86400;
  }
  /* Check the vault */
  if (profile.vars.collection_vault < Page.now) {
    var action = new Timer();
    action.priority = 0;
    action.message = 'Checking vaulted cards...';
    action.type = 'gotourl';
    if (Page.c_page == 'vault' && Page.c_arg == '') {
      var div = Utils.getElementsByXPath('//ul[@class="paging"]//a');
      div = div[div.length-1];
      action.url = div.href;
    } else {
      action.url = 'http://apps.facebook.com/packrat/vault';
    }
    action.append();
    return;
  }
  /* Check vaulted sets */
  if (Page.c_page == 'vault_set') {
    var anchor = Utils.getElementsByXPath('//a[contains(@href,"collection=")]')[0];
    if (anchor) {
      var action = new Timer();
      action.priority = 0;
      action.message = 'Checking ' + anchor.innerHTML;
      action.type = 'gotourl';
      action.url = anchor.href;
      action.append();
    }
  }
}

function collection_preferencesInterface(prefs) {
  if (profile.preferences.collection_work == undefined) profile.preferences.collection_work = new Array();
  var option = new Array();
  option.push('<h2>Collections</h2><hr/>');
  option.push('<label>Collections you are working on:</label><br/>');
  option.push('<table>');
  var count = 0;
  for (var i in collections) {
    if (!collections[i].slug) continue;
    if ((count % 4) == 0) option.push('<tr>');
    option.push('<td><input type="checkbox" name="collection_work" value="' + collections[i].slug + '"');
    if (profile.preferences.collection_work.indexOf(collections[i].slug) != -1) option.push(' checked="checked"');
    option.push('/>');
    option.push('<img style="width: 20px; height: 20px;" src="http://s3.amazonaws.com/afire-packrat/families/' + collections[i].slug + '_family_small.gif"/>');
    option.push(collections[i].name);
    option.push('</td>');
    count++;
    if ((count % 4) == 0) option.push('</tr>');
  }
  if (count % 5) option.push('</tr>');
  option.push('</table>');
  option.push('<br/>');
  var div = document.createElement('div');
  div.innerHTML = option.join('');
  prefs.form.insertBefore(div, prefs.button);
}

function collection_preferencesHandler(form, profile) {
  var col_work = new Array();
  for (var i = 0; i < form.elements.length; i++) {
    var el = form.elements[i];
    if (el.name != 'collection_work') continue;
    if (el.checked) col_work.push(el.value);
  }

  col_work.sort();
  if (col_work.length != profile.preferences.collection_work.length) {
    profile.preferences.collection_work = col_work;
    return true;
  } else {
    for (var i = 0; i < col_work.length; i++) {
      if (col_work[i] != profile.preferences.collection_work[i]) {
        profile.preferences.collection_work = col_work;
        return true;
      }
    }
    return false;
  }
}
/* vim:set tw=80 sts=2 et ft=javascript: */





function highlight_exec() {
  var prefs = profile.preferences;
  var pages = ['user', 'purchase', 'market'];
  if (pages.indexOf(Page.c_page) == -1) return;
  for (var i = 0; i < pagecards.cards.length; i++) {
    var card = pagecards.cards[i];
    if (prefs.highlight_missing) {
      if (prefs.collection_work.indexOf(card.collection) != -1) highlight_enhance(card.wrapper);
    }
    if (prefs.highlight_completed) {
      if (profile.complete_col.indexOf(card.collection) != -1) highlight_delete(card.wrapper);
    }
  }
}

function highlight_enhance(wrapper) {
  try {
    var action = Utils.getElementsByClassName('action', wrapper)[0];
    if (action) action.setAttribute('style', 'background-color: black;');
    var anchor = action.getElementsByTagName('a')[0];
    if (anchor) {
      anchor.setAttribute('style', 'color: white;');
    } else {
      anchor = action.getElementsByTagName('span')[0];
      anchor.setAttribute('style', 'color: white;');
    }
    wrapper.parentNode.insertBefore(wrapper, wrapper.parentNode.firstChild);
  } catch(ex) {dump(ex);}
}

function highlight_delete(wrapper) {
  wrapper.parentNode.removeChild(wrapper);
}

function highlight_preferencesInterface(prefs) {
  if (profile.preferences.highlight_missing == undefined) profile.preferences.highlight_missing = true;
  if (profile.preferences.highlight_completed == undefined) profile.preferences.highlight_completed = true;
  var value = profile.preferences.highlight_missing;
  var option = new Array();
  option.push('<h2>Highlighting</h2><hr/>');
  option.push('<label for="highlight_missing">Highlight cards from working collections:</label>');
  if (value) {
    option.push('Yes <input type="radio" name="highlight_missing" value="1" checked="checked"/>');
    option.push('No <input type="radio" name="highlight_missing" value="0"/>');
  } else {
    option.push('Yes <input type="radio" name="highlight_missing" value="1"/>');
    option.push('No <input type="radio" name="highlight_missing" value="0" checked="checked"/>');
  }
  value = profile.preferences.highlight_completed;
  option.push('<br />');
  option.push('<label for="highlight_completed">Delete cards from completed collections:</label>');
  if (value) {
    option.push('Yes <input type="radio" name="highlight_completed" value="1" checked="checked"/>');
    option.push('No <input type="radio" name="highlight_completed" value="0"/>');
  } else {
    option.push('Yes <input type="radio" name="highlight_completed" value="1"/>');
    option.push('No <input type="radio" name="highlight_completed" value="0" checked="checked"/>');
  }
  option.push('<br />');
  var div = document.createElement('div');
  div.innerHTML = option.join('\n');
  prefs.form.insertBefore(div, prefs.button);
}

function highlight_preferencesHandler(form, profile) {
  var ret = false;
  var input = form.elements.namedItem('highlight_missing');
  if (profile.preferences.highlight_missing != input.checked) {
    profile.preferences.highlight_missing = input.checked;
    ret = true;
  }
  input = form.elements.namedItem('highlight_completed');
  if (profile.preferences.highlight_completed != input.checked) {
    profile.preferences.highlight_completed = input.checked;
    ret = true;
  }
  return ret;
}
/* vim:set tw=80 sts=2 et ft=javascript: */





function grinding_exec() {
  if (!profile.preferences.grinding_enabled) return;
  if (profile.preferences.grinding_level <= profile.level) {
    var idx = profile.vars.browse_module.indexOf('grinding');
    profile.vars.browse_module.splice(idx, 1);
  }
  switch (Page.c_page) {
    case 'user':
      var best, value = 0;
      for (var i = 0; i < pagecards.cards.length; i++) {
        var card = pagecards.cards[i];
        if (card.collection == 'locks' || card.name == 'unknown' || card.collection == 'unknown' || !card.id) continue;
        if (profile.pack_ids.indexOf(card.name) != -1 && card.points > value) {
          best = card;
          value = card.points;
        }
      }
      if (best) {
        var action = new Timer();
        action.priority = 5;
        action.type = 'gotourl';
        action.message = 'Grinding ' + best.name;
        action.url = 'http://apps.facebook.com/packrat/steal/' + best.id;
        action.append();
      }
      break;
    case 'steal':
      /* See if we succeded or failed */
      var notice = document.getElementById('app2431403991_notice-box');
      if (notice) break;
      /* Select the card in our pack to use */
      var steal = pagecards.cards[0];
      if (steal.name == 'unknown') break;
      var drop;
      for (var i = 1; i < pagecards.cards.length; i++) {
        if (pagecards.cards[i].name == steal.name) drop = pagecards.cards[i];
      }
      if (!drop) break;
      /* Select the card and ... */
      var action = new Timer();
      action.priority = 0;
      action.message = 'Selecting card to drop...';
      action.target = drop.wrapper;
      var evt = document.createEvent('MouseEvent');
      evt.initEvent('click', true, true);
      action.event = evt;
      action.append();
      /* ... press the submit button */
      action = new Timer();
      action.priority = 5;
      action.message = 'Stealing the card...';
      var button = document.getElementById('app2431403991_submit_steal');
      action.target = button;
      evt = document.createEvent('MouseEvent');
      evt.initEvent('click', true, true);
      action.event = evt;
      action.append();
      break;
    default:
      break;
  }
}

function grinding_preferencesInterface(prefs) {
  if (profile.preferences.grinding_enabled == undefined) profile.preferences.grinding_enabled = false;
  if (profile.preferences.grinding_level == undefined) profile.preferences.grinding_level = 25;
  var option = new Array();
  var value = profile.preferences.grinding_enabled;
  option.push('<h2>Grinding</h2><hr/>');
  option.push(prefs.addToggleBox('Auto-grind to increase score', 'grinding_enabled', value));
  option.push('<br/>');
  var value = profile.preferences.grinding_level;
  option.push('<label for="grinding_level">Stop grinding at level: </label>');
  option.push('<input name="grinding_level" size="3" maxlength="3" type="text" value="' + value + '"/>');
  var div = document.createElement('div');
  div.innerHTML = option.join('');
  prefs.form.insertBefore(div, prefs.button);
}

function grinding_preferencesHandler(form, profile) {
  var ret = false;
  var input = form.elements.namedItem('grinding_enabled');
  if (profile.preferences.grinding_enabled != input.checked) {
    profile.preferences.grinding_enabled = input.checked;
    ret = true;
  }
  input = form.elements.namedItem('grinding_level');
  input = parseInt(input.value);
  if (profile.preferences.grinding_level != input) {
    profile.preferences.grinding_level = input;
    ret = true;
  }

  var idx;
  idx = profile.vars.browse_module.indexOf('grinding');
  if (profile.preferences.grinding_enabled) {
    if (profile.level < profile.preferences.grinding_level) {
      if (idx == -1) profile.vars.browse_module.push('grinding');
    } else {
      if (idx != -1) profile.vars.browse_module.splice(idx, 1);
    }
  } else {
    if (idx != -1) profile.vars.browse_module.splice(idx, 1);
  }
  return ret;
}
/* vim:set tw=80 sts=2 et ft=javascript: */





function browse_exec() {
  if (profile.vars.browse_pause == undefined) profile.vars.browse_pause = false;
  if (profile.vars.browse_module == undefined) profile.vars.browse_module = new Array();
  if (profile.vars.browse_friends == undefined) profile.vars.browse_friends = new Array();
  if (profile.vars.browse_friendidx == undefined) profile.vars.browse_friendidx = 0;
  if (profile.vars.browse_module.length) {
    if (!profile.vars.browse_pause) {
      window.addEventListener('keydown', browse_pause(true), true);
      var notes = document.getElementById('scriptnotes');
      switch (Page.c_page) {
        case 'friends':
          profile.vars.browse_friends = new Array();
          var div = Utils.getElementsByClassName('name');
          for (var i = 0; i < div.length; i++) {
            var anchor = div[i].getElementsByTagName('a')[0];
            var friend = new Object();
            var id = anchor.href.match(/user\/(.*)/);
            if (id) friend.id = id[1];
            var name = anchor.innerHTML.replace(/<br> /,'');
            friend.name = name;
            profile.vars.browse_friends.push(friend);
          }
          profile.vars.browse_friendidx = 0;
        case 'steal':
          if (Page.c_page == 'steal') {
            var notice = document.getElementById('app2431403991_notice-box');
            if (!notice) break;
          }
        case 'user':
          var idx = profile.vars.browse_friendidx;
          var friend = profile.vars.browse_friends[idx];
          var action = new Timer();
          action.message = 'Browsing to ' + friend.name + ' pack...';
          action.type = 'gotourl';
          action.url = 'http://apps.facebook.com/packrat/user/' + friend.id;
          action.append();
          idx++;
          if (idx < profile.vars.browse_friends.length) {
            profile.vars.browse_friendidx = idx;
          } else {
            profile.vars.browse_friendidx = 0;
          }
          notes.innerHTML += "<li>Press SPACE to pause the cycle</li>";
          break;
        default:
          notes.innerHTML += "<li>Go to 'Your friends' page to start browsing cycle</li>";
          break;
      }
    } else {
      browse_resumelink();
    }
  /* We are not browsing */
  } else {
    profile.vars.browse_pause = false;
  }
}

function browse_pause(handler) {
  if (handler == undefined) handler = true;
  var timer = Timer;
  var resumelink = browse_resumelink;
  var prof = profile;
  return function(ev) {
    if (!handler || ev.keyCode == 32) {
    window.stop();
    window.clearTimeout(timer.timer);
    prof.vars.browse_pause = true;
    prof.save();
    resumelink();
    var stat = document.getElementById('scriptstatus');
    stat.innerHTML = "Script paused...";
    stat = document.getElementById('scripttimer');
    stat.innerHTML = "";
    }
  }
}

function browse_resume() {
  var prof = profile;
  return function(ev) {
    prof.vars.browse_pause = false;
    prof.save()
    location.reload();
  }
}

function browse_resumelink() {
  var error = document.getElementById('scriptresume');
  error.innerHTML = "RESUME BROWSING!<br /><br />";
  error.addEventListener('click', browse_resume(), true);
}

function browse_preferencesInterface(prefs) {
  if (profile.preferences.browse_enabled == undefined) profile.preferences.browse_enabled = false;
  var value = profile.preferences.browse_enabled;
  var option = new Array();
  option.push('<h2>Browsing</h2><hr/>');
  option.push('<label for="browse_enabled">Browse user pages in an infinite loop:</label>');
  if (value) {
    option.push('Yes <input type="radio" name="browse_enabled" value="1" checked="checked"/>');
    option.push('No <input type="radio" name="browse_enabled" value="0"/>');
  } else {
    option.push('Yes <input type="radio" name="browse_enabled" value="1"/>');
    option.push('No <input type="radio" name="browse_enabled" value="0" checked="checked"/>');
  }
  option.push('<br/>');
  var div = document.createElement('div');
  div.innerHTML = option.join('\n');
  prefs.form.insertBefore(div, prefs.button);
}

function browse_preferencesHandler(form, profile) {
  var input = form.elements.namedItem('browse_enabled');
  if (profile.preferences.browse_enabled != input.checked) {
    profile.preferences.browse_enabled = input.checked;
    var idx;
    if (!input.checked &&
        (idx = profile.vars.browse_module.indexOf('browse')) != -1) {
      profile.vars.browse_module.splice(idx, 1);
    } else if (input.checked) profile.vars.browse_module.push('browse');
    return true;
  }
  return false;
}
/* vim:set tw=80 sts=2 et ft=javascript: */

/* Global variables */
var profile;

GM_registerMenuCommand("Reset PackRat's Helper database", function(){
GM_setValue('collections', '({})'); GM_setValue('profile', '({})');});

(function() {
var now, exept;
try {
 now = Date.now();
 profile = new Profile();
 profile.updateData();
  GM_log("*** MODULE 'profile' took " + (Date.now() - now) + " ms ***");
 now = Date.now();
 Preferences.populate(this);
  GM_log("*** MODULE 'preferences' took " + (Date.now() - now) + " ms ***");
 now = Date.now()
} catch(ex) {exept = ex;}

/* Init the menu */
try {
 Menu.init();
 GM_log("*** MODULE 'menu' took " + (Date.now() - now) + " ms ***");
} catch(ex) {
 alert("Error in module 'menu' on line " + ex.lineNumber + ": " + ex.message);
}

if (exept) {
 var error = document.getElementById('scripterror');
 error.innerHTML = "Error in module 'base' on line " + exept.lineNumber + ": " + exept.message + "<br /><br />";
}

for (var i = 0; i < modules.length; i++) {
  if (this[modules[i] + '_exec']) {
    try {
      now = Date.now();
      this[modules[i] + '_exec']();
      GM_log("*** MODULE " + modules[i] + " took " + (Date.now() - now) + " ms ***");
    } catch(ex) {
      var error = document.getElementById('scripterror');
      error.innerHTML = "Error in module '" + modules[i] + "' on line " + ex.lineNumber + ": " + ex.message + "<br /><br />";
    }
  }
}

Timer.start();
profile.save();
}) ();
/* vim:set tw=0 sts=0 sw=2 ts=2 ft=javascript: */
