// This file can be used to customize the functioning of Mozilla's user interface.
// For example code see http://forums.mozillazine.org/viewtopic.php?t=397735 .

/* :::::::: Sub-Script/Overlay Loader v3.0 ::::::::::::::: */

// automatically includes all files ending in .uc.xul and .uc.js from the profile's chrome folder

// New Features:
// supports Greasemonkey-style metadata for userChrome scripts and overlays
// supports a "main" shortcut for the main browser window in include/exclude lines
// supports regexes in the include/exclude lines
// scripts without metadata will run only on the main browser window, for backwards compatibility

if(!userChrome) var userChrome = {js: {}};

(function() {
  // URL of the main browser window;
  var mainWindowURL = "chrome://browser/content/browser.xul";
  
  var chromeDir = Components.classes["@mozilla.org/file/directory_service;1"]
  .getService(Components.interfaces.nsIProperties)
  .get("UChrm", Components.interfaces.nsILocalFile);
  var files = chromeDir.directoryEntries.QueryInterface(Components.interfaces.nsISimpleEnumerator);
  var filepathhandler = Components.classes["@mozilla.org/network/io-service;1"]
  .getService(Components.interfaces.nsIIOService).getProtocolHandler("file")
  .QueryInterface(Components.interfaces.nsIFileProtocolHandler);
  var istream = Components.classes["@mozilla.org/network/file-input-stream;1"]
  .createInstance(Components.interfaces.nsIFileInputStream);  

  userChrome.js.scripts = [];
  userChrome.js.overlays = [];
  
  (function loadFiles() {
    if(!files.hasMoreElements()) return;
    
    var file = files.getNext().QueryInterface(Components.interfaces.nsIFile);
    if(/\.uc(\.js|\.xul)$|^userChrome\.xul$/i.test(file.leafName)) {
      // This code is adapted/simplified from Greasemonkey's scriptdownloader.js and convert2RegExp.js
      var script = {
        filename: file.leafName,
        name: file.leafName,
        namespace: "",
        description: "",
        includes: [],
        excludes: []
      };
      
      // read the file line by line
      var line = {}, foundMeta = false, match = null;
      istream.init(file, 0x01, 0444, 0);
      istream.QueryInterface(Components.interfaces.nsILineInputStream);
      while(istream.readLine(line)) {
        if(!foundMeta && line.value.indexOf("// ==UserScript==") == 0) {
          foundMeta = true;
        }
        else if(foundMeta && (match = line.value.match(/\/\/ \@(\S+)\s+([^\n]+)/))) switch(match[1]) {
          case "name"        : 
          case "namespace"   : 
          case "description" : script[match[1]] = match[2]; break;
          case "include"     : 
          case "exclude"     : script[match[1] + "s"].push(match[2]); break;
        }
        else if(foundMeta && line.value.indexOf("// ==/UserScript==") == 0) {
          break;
        }
      }
      istream.close();
      
      // allow scripts without metadata to run normally
      if(!script.includes.length) script.includes.push(mainWindowURL);
      
      // decide whether to run the script
      var i, run = false, exstart = script.includes.length;
      for(i = 0, list = script.includes.concat(script.excludes); i < list.length; i++) {
        if(list[i] == "main") list[i] = mainWindowURL;
        if(
          list[i] == "*" || 
          list[i][0] == "/" && eval(list[i].replace(/\/\*/, "\/\/")).test(location.href) ||
          convert2RegExp(list[i]).test(location.href)
        ) {
          if(i < exstart)
            run = true;
          else {
            run = false;
            break;
          }
        }
      }
      
      if(run) {
        if(/\.js$/.test(script.filename)) {
          Components.classes["@mozilla.org/moz/jssubscript-loader;1"]
          .getService(Components.interfaces.mozIJSSubScriptLoader)
          .loadSubScript(filepathhandler.getURLSpecFromFile(file));
          userChrome.js.scripts.push(script);
        }
        else {
          document.loadOverlay(filepathhandler.getURLSpecFromFile(file), null);
          userChrome.js.overlays.push(script);
        }
      }
    }
    
    setTimeout(loadFiles, 0);
  })();
  
  
  
  // Converts a pattern in this programs simple notation to a regular expression.
  // thanks AdBlock! http://www.mozdev.org/source/browse/adblock/adblock/
  function convert2RegExp( pattern ) {
    var s = new String(pattern);
    var res = new String("^");
  
    for (var i = 0 ; i < s.length ; i++) {
      switch(s[i]) {
        case '*' :
          res += ".*";
          break;
        case '.' :
        case '?' :
        case '^' :
        case '$' :
        case '+' :
        case '{' :
        case '[' :
        case '|' :
        case '(' :
        case ')' :
        case ']' :
          res += "\\" + s[i];
          break;
        case '\\' :
          res += "\\\\";
          break;
        case ' ' :
          // Remove spaces from URLs.
          break;
        default :
          res += s[i];
          break;
      }
    }
    
    // fortunately, we don't need .tld in chrome :)
    return new RegExp(res + '$', "i");
  }
})();

