(function() {
  var Emitter, Q, Result, ResultsModel, escapeHelper, _,
    __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };

  Q = require('q');

  _ = require('underscore-plus');

  Emitter = require('atom').Emitter;

  escapeHelper = require('../escape-helper');

  Result = (function() {
    Result.create = function(result) {
      var _ref;
      if (result != null ? (_ref = result.matches) != null ? _ref.length : void 0 : void 0) {
        return new Result(result);
      } else {
        return null;
      }
    };

    function Result(result) {
      _.extend(this, result);
    }

    return Result;

  })();

  module.exports = ResultsModel = (function() {
    function ResultsModel(state) {
      var _ref, _ref1, _ref2, _ref3;
      if (state == null) {
        state = {};
      }
      this.onContentsModified = __bind(this.onContentsModified, this);
      this.emitter = new Emitter;
      this.useRegex = (_ref = (_ref1 = state.useRegex) != null ? _ref1 : atom.config.get('find-and-replace.useRegex')) != null ? _ref : false;
      this.caseSensitive = (_ref2 = (_ref3 = state.caseSensitive) != null ? _ref3 : atom.config.get('find-and-replace.caseSensitive')) != null ? _ref2 : false;
      atom.workspace.observeTextEditors((function(_this) {
        return function(editor) {
          return editor.onDidStopChanging(function() {
            return _this.onContentsModified(editor);
          });
        };
      })(this));
      this.clear();
    }

    ResultsModel.prototype.onDidClear = function(callback) {
      return this.emitter.on('did-clear', callback);
    };

    ResultsModel.prototype.onDidClearSearchState = function(callback) {
      return this.emitter.on('did-clear-search-state', callback);
    };

    ResultsModel.prototype.onDidClearReplacementState = function(callback) {
      return this.emitter.on('did-clear-replacement-state', callback);
    };

    ResultsModel.prototype.onDidSearchPaths = function(callback) {
      return this.emitter.on('did-search-paths', callback);
    };

    ResultsModel.prototype.onDidErrorForPath = function(callback) {
      return this.emitter.on('did-error-for-path', callback);
    };

    ResultsModel.prototype.onDidStartSearching = function(callback) {
      return this.emitter.on('did-start-searching', callback);
    };

    ResultsModel.prototype.onDidCancelSearching = function(callback) {
      return this.emitter.on('did-cancel-searching', callback);
    };

    ResultsModel.prototype.onDidFinishSearching = function(callback) {
      return this.emitter.on('did-finish-searching', callback);
    };

    ResultsModel.prototype.onDidStartReplacing = function(callback) {
      return this.emitter.on('did-start-replacing', callback);
    };

    ResultsModel.prototype.onDidFinishReplacing = function(callback) {
      return this.emitter.on('did-finish-replacing', callback);
    };

    ResultsModel.prototype.onDidSearchPath = function(callback) {
      return this.emitter.on('did-search-path', callback);
    };

    ResultsModel.prototype.onDidReplacePath = function(callback) {
      return this.emitter.on('did-replace-path', callback);
    };

    ResultsModel.prototype.onDidChangeReplacementPattern = function(callback) {
      return this.emitter.on('did-change-replacement-pattern', callback);
    };

    ResultsModel.prototype.onDidAddResult = function(callback) {
      return this.emitter.on('did-add-result', callback);
    };

    ResultsModel.prototype.onDidRemoveResult = function(callback) {
      return this.emitter.on('did-remove-result', callback);
    };

    ResultsModel.prototype.onDidFinishSearching = function(callback) {
      return this.emitter.on('did-finish-searching', callback);
    };

    ResultsModel.prototype.serialize = function() {
      return {
        useRegex: this.useRegex,
        caseSensitive: this.caseSensitive
      };
    };

    ResultsModel.prototype.clear = function() {
      this.clearSearchState();
      this.clearReplacementState();
      return this.emitter.emit('did-clear', this.getResultsSummary());
    };

    ResultsModel.prototype.clearSearchState = function() {
      this.pathCount = 0;
      this.matchCount = 0;
      this.regex = null;
      this.results = {};
      this.paths = [];
      this.active = false;
      this.pattern = '';
      this.searchErrors = null;
      if (this.inProgressSearchPromise != null) {
        this.inProgressSearchPromise.cancel();
        this.inProgressSearchPromise = null;
      }
      return this.emitter.emit('did-clear-search-state', this.getResultsSummary());
    };

    ResultsModel.prototype.clearReplacementState = function() {
      this.replacementPattern = null;
      this.replacedPathCount = null;
      this.replacementCount = null;
      this.replacementErrors = null;
      return this.emitter.emit('did-clear-replacement-state', this.getResultsSummary());
    };

    ResultsModel.prototype.search = function(pattern, searchPaths, replacementPattern, _arg) {
      var keepReplacementState, onPathsSearched, onlyRunIfChanged, _ref;
      _ref = _arg != null ? _arg : {}, onlyRunIfChanged = _ref.onlyRunIfChanged, keepReplacementState = _ref.keepReplacementState;
      if (onlyRunIfChanged && (pattern != null) && (searchPaths != null) && pattern === this.pattern && _.isEqual(searchPaths, this.searchedPaths)) {
        return Q();
      }
      if (keepReplacementState) {
        this.clearSearchState();
      } else {
        this.clear();
      }
      this.active = true;
      this.regex = this.getRegex(pattern);
      this.pattern = pattern;
      this.searchedPaths = searchPaths;
      this.updateReplacementPattern(replacementPattern);
      onPathsSearched = (function(_this) {
        return function(numberOfPathsSearched) {
          return _this.emitter.emit('did-search-paths', numberOfPathsSearched);
        };
      })(this);
      this.inProgressSearchPromise = atom.workspace.scan(this.regex, {
        paths: searchPaths,
        onPathsSearched: onPathsSearched
      }, (function(_this) {
        return function(result, error) {
          if (result) {
            return _this.setResult(result.filePath, Result.create(result));
          } else {
            if (_this.searchErrors == null) {
              _this.searchErrors = [];
            }
            _this.searchErrors.push(error);
            return _this.emitter.emit('did-error-for-path', error);
          }
        };
      })(this));
      this.emitter.emit('did-start-searching', this.inProgressSearchPromise);
      return this.inProgressSearchPromise.then((function(_this) {
        return function(message) {
          if (message === 'cancelled') {
            return _this.emitter.emit('did-cancel-searching');
          } else {
            _this.inProgressSearchPromise = null;
            return _this.emitter.emit('did-finish-searching', _this.getResultsSummary());
          }
        };
      })(this));
    };

    ResultsModel.prototype.replace = function(pattern, searchPaths, replacementPattern, replacementPaths) {
      var promise, regex;
      regex = this.getRegex(pattern);
      this.updateReplacementPattern(replacementPattern);
      if (this.useRegex) {
        replacementPattern = escapeHelper.unescapeEscapeSequence(replacementPattern);
      }
      this.active = false;
      this.replacedPathCount = 0;
      this.replacementCount = 0;
      promise = atom.workspace.replace(regex, replacementPattern, replacementPaths, (function(_this) {
        return function(result, error) {
          if (result) {
            if (result.replacements) {
              _this.replacedPathCount++;
              _this.replacementCount += result.replacements;
            }
            return _this.emitter.emit('did-replace-path', result);
          } else {
            if (_this.replacementErrors == null) {
              _this.replacementErrors = [];
            }
            _this.replacementErrors.push(error);
            return _this.emitter.emit('did-error-for-path', error);
          }
        };
      })(this));
      this.emitter.emit('did-start-replacing', promise);
      return promise.then((function(_this) {
        return function() {
          _this.emitter.emit('did-finish-replacing', _this.getResultsSummary());
          return _this.search(pattern, searchPaths, replacementPattern, {
            keepReplacementState: true
          });
        };
      })(this));
    };

    ResultsModel.prototype.updateReplacementPattern = function(replacementPattern) {
      this.replacementPattern = replacementPattern || null;
      return this.emitter.emit('did-change-replacement-pattern', this.regex, replacementPattern);
    };

    ResultsModel.prototype.setActive = function(isActive) {
      if ((isActive && this.pattern) || !isActive) {
        return this.active = isActive;
      }
    };

    ResultsModel.prototype.getActive = function() {
      return this.active;
    };

    ResultsModel.prototype.toggleUseRegex = function() {
      return this.useRegex = !this.useRegex;
    };

    ResultsModel.prototype.toggleCaseSensitive = function() {
      return this.caseSensitive = !this.caseSensitive;
    };

    ResultsModel.prototype.getResultsSummary = function() {
      var pattern;
      pattern = this.pattern || '';
      return {
        pattern: pattern,
        pathCount: this.pathCount,
        matchCount: this.matchCount,
        searchErrors: this.searchErrors,
        replacementPattern: this.replacementPattern,
        replacedPathCount: this.replacedPathCount,
        replacementCount: this.replacementCount,
        replacementErrors: this.replacementErrors
      };
    };

    ResultsModel.prototype.getPathCount = function() {
      return this.pathCount;
    };

    ResultsModel.prototype.getMatchCount = function() {
      return this.matchCount;
    };

    ResultsModel.prototype.getPattern = function() {
      return this.pattern || '';
    };

    ResultsModel.prototype.getPaths = function() {
      return this.paths;
    };

    ResultsModel.prototype.getResult = function(filePath) {
      return this.results[filePath];
    };

    ResultsModel.prototype.setResult = function(filePath, result) {
      if (result) {
        return this.addResult(filePath, result);
      } else {
        return this.removeResult(filePath);
      }
    };

    ResultsModel.prototype.addResult = function(filePath, result) {
      if (this.results[filePath]) {
        this.matchCount -= this.results[filePath].matches.length;
      } else {
        this.pathCount++;
        this.paths.push(filePath);
      }
      this.matchCount += result.matches.length;
      this.results[filePath] = result;
      return this.emitter.emit('did-add-result', {
        filePath: filePath,
        result: result
      });
    };

    ResultsModel.prototype.removeResult = function(filePath) {
      if (this.results[filePath]) {
        this.pathCount--;
        this.matchCount -= this.results[filePath].matches.length;
        this.paths = _.without(this.paths, filePath);
        delete this.results[filePath];
        return this.emitter.emit('did-remove-result', {
          filePath: filePath
        });
      }
    };

    ResultsModel.prototype.getRegex = function(pattern) {
      var flags;
      flags = 'g';
      if (!this.caseSensitive) {
        flags += 'i';
      }
      if (this.useRegex) {
        return new RegExp(pattern, flags);
      } else {
        return new RegExp(_.escapeRegExp(pattern), flags);
      }
    };

    ResultsModel.prototype.onContentsModified = function(editor) {
      var matches, result;
      if (!this.active) {
        return;
      }
      if (!editor.getPath()) {
        return;
      }
      matches = [];
      editor.scan(this.regex, function(match) {
        return matches.push(match);
      });
      result = Result.create({
        matches: matches
      });
      this.setResult(editor.getPath(), result);
      return this.emitter.emit('did-finish-searching', this.getResultsSummary());
    };

    return ResultsModel;

  })();

}).call(this);
