(function() {
  var CLASS_TO_SELECTOR, CLASS_TO_SELECTOR_WITH_BACKWARD_COMPATIBILITY, CLASS_TO_TAG, EDITOR_DESCENDENT_PATTERN, SelectorLinter, eachSelector, path, selectorHasClass, selectorHasPsuedoClass, _, _ref;

  _ = require("underscore-plus");

  path = require("path");

  _ref = require("./helpers"), selectorHasClass = _ref.selectorHasClass, eachSelector = _ref.eachSelector, selectorHasPsuedoClass = _ref.selectorHasPsuedoClass;

  CLASS_TO_TAG = {
    "workspace": "atom-workspace",
    "pane": "atom-pane",
    "panes": "atom-pane-container",
    "editor": "atom-text-editor",
    "editor-colors": "atom-text-editor"
  };

  CLASS_TO_SELECTOR = {
    "pane-row": "atom-pane-axis.horizontal",
    "pane-column": "atom-pane-axis.vertical"
  };

  CLASS_TO_SELECTOR_WITH_BACKWARD_COMPATIBILITY = {
    "overlay": "atom-panel.modal",
    "panel-top": "atom-panel.top",
    "panel-left": "atom-panel.left",
    "panel-right": "atom-panel.right",
    "panel-bottom": "atom-panel.bottom",
    "tool-panel": "atom-panel"
  };

  EDITOR_DESCENDENT_PATTERN = /(\.text-editor|\.editor|\.editor-colors|atom-text-editor)([:.][^ ]+)?[ >].*\w/;

  module.exports = SelectorLinter = (function() {
    function SelectorLinter() {
      this.deprecations = {};
    }

    SelectorLinter.prototype.checkPackage = function(pkg) {
      var keymap, menu, sourcePath, stylesheet, _i, _j, _k, _len, _len1, _len2, _ref1, _ref2, _ref3, _ref4, _ref5, _ref6, _results;
      _ref1 = pkg.menus;
      for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
        _ref2 = _ref1[_i], sourcePath = _ref2[0], menu = _ref2[1];
        this.checkMenu(menu, this.packageMetadata(pkg, sourcePath));
      }
      _ref3 = pkg.keymaps;
      for (_j = 0, _len1 = _ref3.length; _j < _len1; _j++) {
        _ref4 = _ref3[_j], sourcePath = _ref4[0], keymap = _ref4[1];
        this.checkKeymap(keymap, this.packageMetadata(pkg, sourcePath));
      }
      _ref5 = pkg.stylesheets;
      _results = [];
      for (_k = 0, _len2 = _ref5.length; _k < _len2; _k++) {
        _ref6 = _ref5[_k], sourcePath = _ref6[0], stylesheet = _ref6[1];
        if (pkg.metadata["theme"] === "syntax" || /atom-text-editor\.(less|css)/.test(sourcePath)) {
          _results.push(this.checkSyntaxStylesheet(stylesheet, this.packageMetadata(pkg, sourcePath)));
        } else {
          _results.push(this.checkUIStylesheet(stylesheet, this.packageMetadata(pkg, sourcePath)));
        }
      }
      return _results;
    };

    SelectorLinter.prototype.checkKeymap = function(keymap, metadata) {
      var selector, _results;
      _results = [];
      for (selector in keymap) {
        _results.push(this.check(selector, metadata));
      }
      return _results;
    };

    SelectorLinter.prototype.checkUIStylesheet = function(css, metadata) {
      var editorDescendentUsed, klass, replacementSelector, selectorsUsed, shadowSelectorUsed;
      shadowSelectorUsed = editorDescendentUsed = false;
      selectorsUsed = {};
      eachSelector(css, (function(_this) {
        return function(selector) {
          var klass, replacementSelector;
          _this.check(selector, metadata, true);
          for (klass in CLASS_TO_SELECTOR_WITH_BACKWARD_COMPATIBILITY) {
            replacementSelector = CLASS_TO_SELECTOR_WITH_BACKWARD_COMPATIBILITY[klass];
            selectorsUsed[klass] || (selectorsUsed[klass] = selectorHasClass(selector, klass));
            selectorsUsed[replacementSelector] || (selectorsUsed[replacementSelector] = selector.indexOf(replacementSelector) >= 0);
          }
          editorDescendentUsed || (editorDescendentUsed = EDITOR_DESCENDENT_PATTERN.test(selector));
          return shadowSelectorUsed || (shadowSelectorUsed = selectorHasPsuedoClass(selector, ":shadow"));
        };
      })(this));
      for (klass in CLASS_TO_SELECTOR_WITH_BACKWARD_COMPATIBILITY) {
        replacementSelector = CLASS_TO_SELECTOR_WITH_BACKWARD_COMPATIBILITY[klass];
        if (selectorsUsed[klass] && !selectorsUsed[replacementSelector]) {
          this.addDeprecation(metadata, "Use the selector `" + replacementSelector + "` instead of the `" + klass + "` class.");
        }
      }
      if (editorDescendentUsed && !shadowSelectorUsed) {
        return this.addDeprecation(metadata, "Style elements within text editors using the `atom-text-editor::shadow` selector or the `.atom-text-editor.less` file extension.\nIf you want to target overlay elements, target them directly or as descendants of `atom-overlay` elements.");
      }
    };

    SelectorLinter.prototype.checkSyntaxStylesheet = function(css, metadata) {
      var editorClassUsed, editorColorsClassUsed, hostSelectorUsed;
      hostSelectorUsed = editorClassUsed = editorColorsClassUsed = false;
      eachSelector(css, (function(_this) {
        return function(selector) {
          _this.check(selector, metadata);
          editorClassUsed || (editorClassUsed = selectorHasClass(selector, "editor"));
          editorColorsClassUsed || (editorColorsClassUsed = selectorHasClass(selector, "editor-colors"));
          return hostSelectorUsed || (hostSelectorUsed = selectorHasPsuedoClass(selector, "host"));
        };
      })(this));
      if (!hostSelectorUsed) {
        if (editorClassUsed) {
          this.addDeprecation(metadata, "Target the selector `:host, atom-text-editor` instead of `.editor` for shadow DOM support.");
        }
        if (editorColorsClassUsed) {
          return this.addDeprecation(metadata, "Target the selector `:host, atom-text-editor` instead of `.editor-colors` for shadow DOM support.");
        }
      }
    };

    SelectorLinter.prototype.checkMenu = function(menu, metadata) {
      var selector, _results;
      _results = [];
      for (selector in menu['context-menu']) {
        _results.push(this.check(selector, metadata));
      }
      return _results;
    };

    SelectorLinter.prototype.check = function(selector, metadata, skipBackwardCompatible) {
      var klass, replacement, tag;
      if (skipBackwardCompatible == null) {
        skipBackwardCompatible = false;
      }
      for (klass in CLASS_TO_TAG) {
        tag = CLASS_TO_TAG[klass];
        if (selectorHasClass(selector, klass)) {
          this.addDeprecation(metadata, "Use the `" + tag + "` tag instead of the `" + klass + "` class.");
        }
      }
      for (klass in CLASS_TO_SELECTOR) {
        replacement = CLASS_TO_SELECTOR[klass];
        if (selectorHasClass(selector, klass)) {
          this.addDeprecation(metadata, "Use the selector `" + replacement + "` instead of the `" + klass + "` class.");
        }
      }
      if (!skipBackwardCompatible) {
        for (klass in CLASS_TO_SELECTOR_WITH_BACKWARD_COMPATIBILITY) {
          replacement = CLASS_TO_SELECTOR_WITH_BACKWARD_COMPATIBILITY[klass];
          if (selectorHasClass(selector, klass)) {
            this.addDeprecation(metadata, "Use the selector `" + replacement + "` instead of the `" + klass + "` class.");
          }
        }
      }
      if (selectorHasClass(selector, "editor") && selectorHasClass(selector, "mini")) {
        this.addDeprecation(metadata, "Use the selector `atom-text-editor[mini]` to select mini-editors.");
      }
      if (selectorHasClass(selector, "bracket-matcher") && !selectorHasClass(selector, "region")) {
        return this.addDeprecation(metadata, "Use `.bracket-matcher .region` to select highlighted brackets.");
      }
    };

    SelectorLinter.prototype.clearDeprecations = function() {
      return this.deprecations = {};
    };

    SelectorLinter.prototype.getDeprecations = function() {
      return this.deprecations;
    };

    SelectorLinter.prototype.packageMetadata = function(pkg, sourcePath) {
      return {
        packageName: pkg.name,
        packagePath: pkg.path,
        sourcePath: path.relative(pkg.path, sourcePath)
      };
    };

    SelectorLinter.prototype.addDeprecation = function(metadata, message) {
      var deprecation, fileDeprecations, packageName, sourcePath, _base, _base1;
      packageName = metadata.packageName, sourcePath = metadata.sourcePath;
      if ((_base = this.deprecations)[packageName] == null) {
        _base[packageName] = {};
      }
      fileDeprecations = (_base1 = this.deprecations[packageName])[sourcePath] != null ? _base1[sourcePath] : _base1[sourcePath] = [];
      deprecation = _.extend(_.omit(metadata, "packageName", "sourcePath"), {
        message: message
      });
      if (!_.any(fileDeprecations, function(existing) {
        return _.isEqual(existing, deprecation);
      })) {
        return fileDeprecations.push(deprecation);
      }
    };

    return SelectorLinter;

  })();

}).call(this);
