(function() {
  var CompositeDisposable, GitDiffView, repositoryForPath,
    __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };

  CompositeDisposable = require('atom').CompositeDisposable;

  repositoryForPath = require('./helpers').repositoryForPath;

  module.exports = GitDiffView = (function() {
    function GitDiffView(editor) {
      var editorElement, editorView;
      this.editor = editor;
      this.updateDiffs = __bind(this.updateDiffs, this);
      this.subscriptions = new CompositeDisposable();
      this.decorations = {};
      this.markers = [];
      this.subscriptions.add(this.editor.onDidStopChanging(this.updateDiffs));
      this.subscriptions.add(this.editor.onDidChangePath(this.updateDiffs));
      this.subscribeToRepository();
      this.subscriptions.add(atom.project.onDidChangePaths((function(_this) {
        return function() {
          return _this.subscribeToRepository();
        };
      })(this)));
      this.subscriptions.add(this.editor.onDidDestroy((function(_this) {
        return function() {
          _this.cancelUpdate();
          _this.removeDecorations();
          return _this.subscriptions.dispose();
        };
      })(this)));
      editorView = atom.views.getView(this.editor);
      this.subscriptions.add(atom.commands.add(editorView, 'git-diff:move-to-next-diff', (function(_this) {
        return function() {
          return _this.moveToNextDiff();
        };
      })(this)));
      this.subscriptions.add(atom.commands.add(editorView, 'git-diff:move-to-previous-diff', (function(_this) {
        return function() {
          return _this.moveToPreviousDiff();
        };
      })(this)));
      this.subscriptions.add(atom.config.onDidChange('git-diff.showIconsInEditorGutter', (function(_this) {
        return function() {
          return _this.updateIconDecoration();
        };
      })(this)));
      this.subscriptions.add(atom.config.onDidChange('editor.showLineNumbers', (function(_this) {
        return function() {
          return _this.updateIconDecoration();
        };
      })(this)));
      editorElement = atom.views.getView(this.editor);
      this.subscriptions.add(editorElement.onDidAttach((function(_this) {
        return function() {
          return _this.updateIconDecoration();
        };
      })(this)));
      this.updateIconDecoration();
      this.scheduleUpdate();
    }

    GitDiffView.prototype.moveToNextDiff = function() {
      var cursorLineNumber, firstDiffLineNumber, newStart, nextDiffLineNumber, _i, _len, _ref, _ref1;
      cursorLineNumber = this.editor.getCursorBufferPosition().row + 1;
      nextDiffLineNumber = null;
      firstDiffLineNumber = null;
      _ref1 = (_ref = this.diffs) != null ? _ref : [];
      for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
        newStart = _ref1[_i].newStart;
        if (newStart > cursorLineNumber) {
          if (nextDiffLineNumber == null) {
            nextDiffLineNumber = newStart - 1;
          }
          nextDiffLineNumber = Math.min(newStart - 1, nextDiffLineNumber);
        }
        if (firstDiffLineNumber == null) {
          firstDiffLineNumber = newStart - 1;
        }
        firstDiffLineNumber = Math.min(newStart - 1, firstDiffLineNumber);
      }
      if (nextDiffLineNumber == null) {
        nextDiffLineNumber = firstDiffLineNumber;
      }
      return this.moveToLineNumber(nextDiffLineNumber);
    };

    GitDiffView.prototype.updateIconDecoration = function() {
      var gutter, _ref;
      gutter = (_ref = atom.views.getView(this.editor).rootElement) != null ? _ref.querySelector('.gutter') : void 0;
      if (atom.config.get('editor.showLineNumbers') && atom.config.get('git-diff.showIconsInEditorGutter')) {
        return gutter != null ? gutter.classList.add('git-diff-icon') : void 0;
      } else {
        return gutter != null ? gutter.classList.remove('git-diff-icon') : void 0;
      }
    };

    GitDiffView.prototype.moveToPreviousDiff = function() {
      var cursorLineNumber, lastDiffLineNumber, newStart, previousDiffLineNumber, _i, _len, _ref, _ref1;
      cursorLineNumber = this.editor.getCursorBufferPosition().row + 1;
      previousDiffLineNumber = -1;
      lastDiffLineNumber = -1;
      _ref1 = (_ref = this.diffs) != null ? _ref : [];
      for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
        newStart = _ref1[_i].newStart;
        if (newStart < cursorLineNumber) {
          previousDiffLineNumber = Math.max(newStart - 1, previousDiffLineNumber);
        }
        lastDiffLineNumber = Math.max(newStart - 1, lastDiffLineNumber);
      }
      if (previousDiffLineNumber === -1) {
        previousDiffLineNumber = lastDiffLineNumber;
      }
      return this.moveToLineNumber(previousDiffLineNumber);
    };

    GitDiffView.prototype.moveToLineNumber = function(lineNumber) {
      if (lineNumber == null) {
        lineNumber = -1;
      }
      if (lineNumber >= 0) {
        this.editor.setCursorBufferPosition([lineNumber, 0]);
        return this.editor.moveToFirstCharacterOfLine();
      }
    };

    GitDiffView.prototype.subscribeToRepository = function() {
      if (this.repository = repositoryForPath(this.editor.getPath())) {
        this.subscriptions.add(this.repository.onDidChangeStatuses((function(_this) {
          return function() {
            return _this.scheduleUpdate();
          };
        })(this)));
        return this.subscriptions.add(this.repository.onDidChangeStatus((function(_this) {
          return function(changedPath) {
            if (changedPath === _this.editor.getPath()) {
              return _this.scheduleUpdate();
            }
          };
        })(this)));
      }
    };

    GitDiffView.prototype.cancelUpdate = function() {
      return clearImmediate(this.immediateId);
    };

    GitDiffView.prototype.scheduleUpdate = function() {
      this.cancelUpdate();
      return this.immediateId = setImmediate(this.updateDiffs);
    };

    GitDiffView.prototype.updateDiffs = function() {
      var path, _ref, _ref1;
      if (this.editor.isDestroyed()) {
        return;
      }
      this.removeDecorations();
      if (path = (_ref = this.editor) != null ? _ref.getPath() : void 0) {
        if (this.diffs = (_ref1 = this.repository) != null ? _ref1.getLineDiffs(path, this.editor.getText()) : void 0) {
          return this.addDecorations(this.diffs);
        }
      }
    };

    GitDiffView.prototype.addDecorations = function(diffs) {
      var endRow, newLines, newStart, oldLines, oldStart, startRow, _i, _len, _ref;
      for (_i = 0, _len = diffs.length; _i < _len; _i++) {
        _ref = diffs[_i], oldStart = _ref.oldStart, newStart = _ref.newStart, oldLines = _ref.oldLines, newLines = _ref.newLines;
        startRow = newStart - 1;
        endRow = newStart + newLines - 2;
        if (oldLines === 0 && newLines > 0) {
          this.markRange(startRow, endRow, 'git-line-added');
        } else if (newLines === 0 && oldLines > 0) {
          this.markRange(startRow, startRow, 'git-line-removed');
        } else {
          this.markRange(startRow, endRow, 'git-line-modified');
        }
      }
    };

    GitDiffView.prototype.removeDecorations = function() {
      var marker, _i, _len, _ref;
      _ref = this.markers;
      for (_i = 0, _len = _ref.length; _i < _len; _i++) {
        marker = _ref[_i];
        marker.destroy();
      }
      return this.markers = [];
    };

    GitDiffView.prototype.markRange = function(startRow, endRow, klass) {
      var marker;
      marker = this.editor.markBufferRange([[startRow, 0], [endRow, Infinity]], {
        invalidate: 'never'
      });
      this.editor.decorateMarker(marker, {
        type: 'line-number',
        "class": klass
      });
      return this.markers.push(marker);
    };

    return GitDiffView;

  })();

}).call(this);
