// ADV Multiquoter
// version 1.2
// Release Date: 2009-12-23
// http://bolty.net/from/advrider
// Copyright (c) 2009, Stacy Brock, All Rights Reserved (unless otherwise noted...)
//
// You may modify this script for your own personal use,
// but please contact me first before releasing any changes.
// Don't be an asshat.
//
// ***** INSTRUCTIONS *****
//
// 
// ==UserScript==
// @name           ADV Multiquoter
// @namespace      http://bolty.net/from/advrider
// @description    Adds support for multiquoting, i.e. quote from multiple posts.
//
// @include        http://www.advrider.com/*
// @include        http://advrider.com/*
// ==/UserScript==

/* Querystring class
 *
 * Copyright (c) 2008, Adam Vandenberg
 * All rights reserved.
 * http://adamv.com/dev/javascript/querystring
 *
 * Client-side access to querystring name=value pairs
 * Version 1.3
 * 28 May 2008
 *
 * License (Simplified BSD):
 * http://adamv.com/dev/javascript/qslicense.txt
 */
function Querystring(qs) { // optionally pass a querystring to parse
  this.params = {};

  if (qs == null) qs = location.search.substring(1, location.search.length);
  if (qs.length == 0) return;

  // Turn <plus> back to <space>
  // See: http://www.w3.org/TR/REC-html40/interact/forms.html#h-17.13.4.1
  qs = qs.replace(/\+/g, ' ');
  var args = qs.split('&'); // parse out name/value pairs separated via &

  // split out each name=value pair
  for (var i = 0; i < args.length; i++) {
    var pair = args[i].split('=');
    var name = decodeURIComponent(pair[0]);

    var value = (pair.length==2)
    ? decodeURIComponent(pair[1])
    : name;

    this.params[name] = value;
  }
}

Querystring.prototype.get = function(key, default_) {
  var value = this.params[key];
  return (value != null) ? value : default_;
}

Querystring.prototype.contains = function(key) {
  var value = this.params[key];
  return (value != null);
}
/* end of Querystring class */


/* xpath helper function
 * from http://wiki.greasespot.net/Code_snippets
 */
function $x() {
  var x='',          // default values
  node=document,
  type=0,
  fix=true,
  i=0,
  toAr=function(xp){      // XPathResult to array
    var final=[], next;
    while(next=xp.iterateNext())
      final.push(next);
    return final
  },
  cur;
  while (cur=arguments[i++])      // argument handler
    switch(typeof cur) {
  case "string":x+=(x=='') ? cur : " | " + cur;continue;
  case "number":type=cur;continue;
  case "object":node=cur;continue;
  case "boolean":fix=cur;continue;
  }
  if (fix) {      // array conversion logic
    if (type==6) type=4;
    if (type==7) type=5;
  }
  if (!/^\//.test(x)) x="//"+x;            // selection mistake helper
  if (node!=document && !/^\./.test(x)) x="."+x;  // context mistake helper
  var temp=document.evaluate(x,node,null,type,null); //evaluate!
  if (fix)
    switch(type) {                              // automatically return special type
  case 1:return temp.numberValue;
  case 2:return temp.stringValue;
  case 3:return temp.booleanValue;
  case 8:return temp.singleNodeValue;
  case 9:return temp.singleNodeValue;
  }
  return fix ? toAr(temp) : temp;
}
/* end of xpath helper function */


/* begin ADV Multiquoter code */

var advMQ = {
  addQuoteLinks: function () {
    var quotebarArr = $x("//td[@class = 'alt1' and @align='right']", XPathResult.ORDERED_NODE_SNAPSHOT_TYPE);
    quotebarArr.forEach(
      function(td) {
        // get post ID from quote or edit button
        var a = td.childNodes[3];
        var match = /p=(\d+)/(a.href);
        if (match != null) {
          var postId = match[1];
        }

        // deserialize quote cache
        advMQ.quotes = advMQ.deserialize("quotecache");

        // create multiquote checkbox
        var mqDiv = document.createElement("span");
        mqDiv.id = "advMQ_quote_" + postId;
        mqDiv.className = "smallfont";
        var multiquoteLink = "<a href=\"/forums/newreply.php?do=newreply&multiquote=1&p=" + postId + "\">multiquote</a>";
        if (advMQ.isQuoted(postId)) {
          mqDiv.innerHTML = " <input type='checkbox' id='advMQ_chk_" + postId + "' name='' onclick=\"advMQ_toggleQuote(" + postId + ");\" checked> [" + multiquoteLink + "]";
        } else {
          mqDiv.innerHTML = " <input type='checkbox' id='advMQ_chk_" + postId + "' name='' onclick=\"advMQ_toggleQuote(" + postId + ");\"> [" + multiquoteLink + "]";
        }
        td.appendChild(mqDiv);
      }
    );
  },
  getRealQuote: function (postId) {
    window.setTimeout(function () { GM_xmlhttpRequest(
          {
            method: 'GET',
            url: 'http://advrider.com/forums/newreply.php?do=newreply&p=' + postId,
            headers: {
              'User-agent': 'Mozilla/4.0 (compatible) Greasemonkey',
              'Accept': 'text/html',
              'Cookie': document.cookie,
            },
            onload: function(response) {
              //GM_log('Request for page returned ' + response.status + ' ' + response.statusText + '\n\n' + 'Page data:\n' + response.responseText);
              //GM_log('Request for page returned ' + response.status + ' ' + response.statusText);
              var match = /<textarea[\s\S]*?id="vB_Editor_001_textarea"[\s\S]*?>([\s\S]*?)<\/textarea>/(response.responseText);
              if (match != null) {
                advMQ.quotes.push(new Array(postId, match[1]));
                //GM_log(advMQ.quotes);
                advMQ.serialize("quotecache", advMQ.quotes);
              } else {
                //GM_log("no match");
              }
            }
          }
        );
      }, 0);
  },
  isQuoted: function (postId) {
    for (var i = 0; i < advMQ.quotes.length; i++) {
      if (advMQ.quotes[i][0] == postId) {
        return true;
      }
    }
  },
  removeQuote: function (postId) {
    for (var i = 0; i < advMQ.quotes.length; i++) {
      var quote = advMQ.quotes[i];
      if (quote[0] == postId) {
        advMQ.quotes.splice(i, 1);
      }
    }
    advMQ.serialize("quotecache", advMQ.quotes);
    //GM_log(advMQ.quotes);
  },
  insertQuotes: function () {
    var quotes = advMQ.deserialize("quotecache");
    // plain \n version
    var theQuote = "";
    var quoteStr = "";
    // wysiwyg version (<br/> tagged)
    var theQuoteBr = "";
    var quoteStrBr = "";

    // concat quotes into strings
    for (var i = 0; i < quotes.length; i++) {
      theQuote = quotes[i][1];
      theQuoteBr = quotes[i][1].replace(/\n/gi, "<br/>");
      //GM_log("linebreaked: " + theQuote);
      //quoteStr = quoteStr + quotes[i][1] + "<br/><br/>";
      quoteStr = quoteStr + theQuote + "\n\n";
      quoteStrBr = quoteStrBr + theQuoteBr + "<br/><br/>";
    }

    var wysiwyg = $x("//html/body[@class='wysiwyg']", XPathResult.FIRST_ORDERED_NODE_TYPE);
    if (wysiwyg != null) {
      wysiwyg.innerHTML = quoteStrBr;
    }
    
    var textarea = $x("//textarea[@id='vB_Editor_001_textarea']", XPathResult.FIRST_ORDERED_NODE_TYPE);
    if (textarea != null) {
      textarea.value = quoteStr;
    }

    // now that both textareas have loaded, we can clear the quote cache
    advMQ.clearQuotes();
  },
  clearQuotes: function () {
    advMQ.quotes = [];
    advMQ.serialize("quotecache", advMQ.quotes);
  },
  deserialize: function (name, def) {
    return eval(GM_getValue(name, (def ? def : '({})')) );
  },
  serialize: function (name, val) {
    window.setTimeout( function() { GM_setValue(name, uneval(val)) }, 0);
  },
  showError: function (message) {
    var newNode = document.createElement("div");
    newNode.innerHTML = message;
    var target = $x("/html/body/div/div/div/table[2]//tr/td[1]", XPathResult.ANY_UNORDERED_NODE_TYPE);
    target.appendChild(newNode);
  },
  quotes: [],
} // end advMQ

// add functions to global window
if (typeof(unsafeWindow) == "undefined") { unsafeWindow = window; }
unsafeWindow.advMQ_toggleQuote = function(postId) {
  var checkbox = document.getElementById('advMQ_chk_' + postId);
  if (checkbox.checked) {
    advMQ.getRealQuote(postId);
  } else {
    advMQ.removeQuote(postId);
  }
}

// This script requires the GM_getValue function implemented in GM 0.3 or above
if(GM_getValue) {
  // get current query string
  var queryStr = new Querystring();

  if (queryStr.get("do") == "newreply" && queryStr.get("multiquote") == "1") {
    advMQ.insertQuotes();
  } else {
    // are we even viewing a thread?
    if (queryStr.contains("t") || queryStr.contains("p")) {
      // yep
      advMQ.addQuoteLinks();
    } else {
      // nope, so GTFO
      return;
    }
  }
} else {
  advMQ.showError("ADV Multiquoter error: GreaseMonkey version 0.3 or higher required");
}

