// Caching plugin for jQuery. Use $.cache(selector) instead of $(selector) to save and retrieve elements from the cache.
// Use $.cache.flush() to empty it
// selector must be a string.
// Notes:
// Is sophisticated about caching; $('body div > img') will cache and use the cache for
// $('body'), $('body div') and $('body div > img')
// Very little error checking. Bad selector syntax may fail in mysterious ways, mostly silent.
// Uses the window context exclusively (no support for $(selector, context) kinds of things)
// Newlines in the selector will work in the sense that it will return the correct jQuery object but it defeats the sophisticated
// parsing

(function($){
  var cache = {};
  $.cache = function (selector){
    return cache[selector] || scanCache(munge(selector));
  };
  $.cache.flush = function() {cache={}; munged={}; uid=0;};
  $.cache.log = function() {console.log(cache)}

  function scanCache (selector){ // parse the selector and search the cache for the parts. Selector must have parentheticals munged first and all newlines turned to spaces
    // split the comma parts
    if (/,/.test(selector)) return flatten($.map(selector.split(','), scanCache));
    var restored = restore (selector);
    if (cache[restored]) return cache[restored];
    // note on the following: simple selectors end with \w or a parenthetical (which have all been munged into `number`)
    // and joiners are \s+~> 
    var split = /^(.*[\w`])([\s+~>]+[^\s+~>]+)\s*$/.exec(selector); // split the selector into last child and parent parts
    return cache[restored] = split ? $(restore(split[2]), scanCache(split[1])) : $(restored);
  }

  function flatten (arr){ // turns an array of jQuery objects into one. I thought $() would do this automatically!
    for (var ret = arr.shift(); arr.length; ret = ret.add(arr.shift()));
    return ret;
  }

  // matches quotes (double and single), parentheses and square brackets
  var REparens = /("([^\\\"]|\\.)*"|'([^\\\']|\\.)*')|(\(([^\\)(]|\\.)*\))|(\[([^\\\]\[]|\\.)*\])/;
  var REmunged = /(`\d+`)/;

  var munged = {};
  var uid = 0; // unique id
  // remove strings and parentheticals; could be more efficient: now it uses the RE twice
  function munge(str){
    while (match = REparens.exec(str)){
      var replacement = '`'+(uid++)+'`';
      munged[replacement] = match[0];
      str = str.replace(REparens, replacement);
    }
    return str;
  }
  function restore(str){
    while (match = REmunged.exec(str)){
      str = str.replace(REmunged, munged[match[1]]);
    }
    return str;
  }
})(jQuery)
