/*global Storage, Logger, jQuery, js_beautify, Utils */
/*eslint no-new-func:0, max-nested-callbacks:[1,4]*/
"use strict";

/* A single Rule */
var Rule = function() {
  this.prettyPrint = function() {
    var clone = jQuery.extend({}, this);
    delete clone.matcher;
    return JSON.stringify(clone, null, 2);
  };

  this.prettyPrintHtml = function() {
    return this.prettyPrint().replace(/\n/,"<br />");
  };
};

Rule.create = function(options, tabId, ruleIndex) {
  var rule = new Rule();
  Object.keys(options).forEach(function(key) {
    rule[key] = options[key];
  });
  rule.matcher = new RegExp(rule.url);
  rule.nameClean = rule.name.replace("<", "&lt;");
  rule.urlClean = rule.url.toString();
  rule.id = tabId + "-" + ruleIndex;
  Logger.info("[rule.js] created rule", rule);
  return rule;
};

/* Multiple Rules */
var Rules = {
  ruleCount: 0,
  matchesForUrl: function(url) {
    var rules = this;
    return new Promise(function (resolve) {
      rules.all().then(function(rules) {
        var matchingRules = rules.filter(function (rule) {
          return url.match(rule.matcher);
        });
        resolve(matchingRules);
      });
    });
  },
  load: function(forTabId) {
    var that = this;
    return new Promise(function (resolve) {
      Storage.load(that._nameForTabId(forTabId)).then(function (rulesCode) {
        var rules = [];
        if(rulesCode) {
          // remove wrapper
          var rulesCodeMatches = rulesCode.match(/^.*?(\[[\s\S]*\];)$/m);

          // This should not happen:
          if(!rulesCodeMatches[1]) {
            resolve(rules);
          }

          // Now we go into hell ...
          // TODO: remove unsafe-eval from manifest and use a chrome sandbox iframe
          var ruleCode = "return " + rulesCodeMatches[1].replace(/\\n/g,"");
          var ruleFunction = new Function(ruleCode);
          that.ruleCount = 0;

          rules = ruleFunction().map(function (ruleJson, index) {
            that.ruleCount += 1;
            return Rule.create(ruleJson, forTabId, index);
          });
        }
        resolve(rules);
      });
    });
  },
  all: function() {
    return new Promise(function (resolve) {
      Logger.info("[rules.js] Fetching all rules");
      Storage.load(Utils.keys.tabs).then(function(tabSettings) {
        var promises = [];
        var rules = [];

        // Generate a Promise for all tab to be loaded
        tabSettings.forEach(function (tabSetting) {
          promises.push(Rules.load(tabSetting.id));
        });

        // Wait until resolved
        Promise.all(promises).then(function (values) {
          // Outer loop: An array of arrays of rules [[Rule, Rule], [Rule, Rule]]
          values.forEach(function (ruleSetForTab) {
            // Inner Loop: An array of rules [Rule, Rule]
            ruleSetForTab.forEach(function (ruleSet) {
              rules.push(ruleSet);
            });
          });
          Logger.info("[rules.js] Fetched " + rules.length + " rules");
          resolve(rules);
        });
      });
    });
  },
  save: function(ruleCode, activeTabId) {
    return new Promise(function (resolve) {
      Storage.save(ruleCode, Rules._nameForTabId(activeTabId)).then(function () {
        resolve(true);
      });
    });
  },
  delete: function(tabId) {
    Storage.delete(this._nameForTabId(tabId));
  },
  _nameForTabId: function(tabId) {
    return Utils.keys.rules + "-tab-" + tabId;
  },
  format: function(rulesCodeString) {
    // Prettify code a little
    var prettyCode = js_beautify(rulesCodeString, {
      "indent_size": 2,
      "indent_char": " ",
      "preserve_newlines": false,
      "brace_style": "expand",
      "space_before_conditional": true,
      "unescape_strings": false
    });
    if(/\}\];$/.test(prettyCode)) {
      prettyCode = prettyCode.replace(/\}\];$/, "}\n];");
    }
    return prettyCode;
  },
  // Simple checks for the neccessary structure of the rules
  syntaxCheck: function(editor) {
    var errors = [];

    // Check if there are some ACE Annotations (aka. errors) present
    var annotationCount =  editor.session().getAnnotations().length;
    if(annotationCount > 0) {
      errors.push("annotations-present");
    }

    // Check structure of rules code
    if(!/^(var\s+)?([a-z_])+\s+=\s+\[\s?$/i.test(editor.session().getLine(0)) ||
       !/^\s*\];\s*$/.test(editor.session().getLine(editor.session().getLength() - 1))) {
      errors.push("var-needed");
    }

    return errors;
  }
};


@@ -262,16 +262,92 @@
 atcher;%0A
+    delete clone.nameClean;%0A    delete clone.urlClean;%0A    delete clone.id;%0A
     retu

remove some data for rule extraction