(function() {
  var CompositeDisposable, SnippetExpansion, _;

  _ = require('underscore-plus');

  CompositeDisposable = require('atom').CompositeDisposable;

  module.exports = SnippetExpansion = (function() {
    SnippetExpansion.prototype.settingTabStop = false;

    function SnippetExpansion(snippet, editor, cursor, snippets) {
      var startPosition;
      this.snippet = snippet;
      this.editor = editor;
      this.cursor = cursor;
      this.snippets = snippets;
      this.subscriptions = new CompositeDisposable;
      this.tabStopMarkers = [];
      this.selections = [this.cursor.selection];
      startPosition = this.cursor.selection.getBufferRange().start;
      this.editor.transact((function(_this) {
        return function() {
          var newRange;
          newRange = _this.editor.transact(function() {
            return _this.cursor.selection.insertText(snippet.body, {
              autoIndent: false
            });
          });
          if (snippet.tabStops.length > 0) {
            _this.subscriptions.add(_this.cursor.onDidChangePosition(function(event) {
              return _this.cursorMoved(event);
            }));
            _this.subscriptions.add(_this.cursor.onDidDestroy(function() {
              return _this.cursorDestroyed();
            }));
            _this.placeTabStopMarkers(startPosition, snippet.tabStops);
            _this.snippets.addExpansion(_this.editor, _this);
            _this.editor.normalizeTabsInBufferRange(newRange);
          }
          if (snippet.lineCount > 1) {
            return _this.indentSubsequentLines(startPosition.row, snippet);
          }
        };
      })(this));
    }

    SnippetExpansion.prototype.cursorMoved = function(_arg) {
      var newBufferPosition, newTabStops, oldBufferPosition, oldTabStops, textChanged;
      oldBufferPosition = _arg.oldBufferPosition, newBufferPosition = _arg.newBufferPosition, textChanged = _arg.textChanged;
      if (this.settingTabStop || textChanged) {
        return;
      }
      oldTabStops = this.tabStopsForBufferPosition(oldBufferPosition);
      newTabStops = this.tabStopsForBufferPosition(newBufferPosition);
      if (!_.intersection(oldTabStops, newTabStops).length) {
        return this.destroy();
      }
    };

    SnippetExpansion.prototype.cursorDestroyed = function() {
      if (!this.settingTabStop) {
        return this.destroy();
      }
    };

    SnippetExpansion.prototype.placeTabStopMarkers = function(startPosition, tabStopRanges) {
      var ranges, _i, _len;
      for (_i = 0, _len = tabStopRanges.length; _i < _len; _i++) {
        ranges = tabStopRanges[_i];
        this.tabStopMarkers.push(ranges.map((function(_this) {
          return function(_arg) {
            var end, start;
            start = _arg.start, end = _arg.end;
            return _this.editor.markBufferRange([startPosition.traverse(start), startPosition.traverse(end)]);
          };
        })(this)));
      }
      return this.setTabStopIndex(0);
    };

    SnippetExpansion.prototype.indentSubsequentLines = function(startRow, snippet) {
      var initialIndent, row, _i, _ref, _ref1, _results;
      initialIndent = this.editor.lineTextForBufferRow(startRow).match(/^\s*/)[0];
      _results = [];
      for (row = _i = _ref = startRow + 1, _ref1 = startRow + snippet.lineCount; _ref <= _ref1 ? _i < _ref1 : _i > _ref1; row = _ref <= _ref1 ? ++_i : --_i) {
        _results.push(this.editor.buffer.insert([row, 0], initialIndent));
      }
      return _results;
    };

    SnippetExpansion.prototype.goToNextTabStop = function() {
      var nextIndex;
      nextIndex = this.tabStopIndex + 1;
      if (nextIndex < this.tabStopMarkers.length) {
        if (this.setTabStopIndex(nextIndex)) {
          return true;
        } else {
          return this.goToNextTabStop();
        }
      } else {
        this.destroy();
        return false;
      }
    };

    SnippetExpansion.prototype.goToPreviousTabStop = function() {
      if (this.tabStopIndex > 0) {
        return this.setTabStopIndex(this.tabStopIndex - 1);
      }
    };

    SnippetExpansion.prototype.setTabStopIndex = function(tabStopIndex) {
      var i, marker, markerSelected, newSelection, range, ranges, selection, _i, _j, _k, _len, _len1, _len2, _ref, _ref1;
      this.tabStopIndex = tabStopIndex;
      this.settingTabStop = true;
      markerSelected = false;
      ranges = [];
      _ref = this.tabStopMarkers[this.tabStopIndex];
      for (_i = 0, _len = _ref.length; _i < _len; _i++) {
        marker = _ref[_i];
        if (marker.isValid()) {
          ranges.push(marker.getBufferRange());
        }
      }
      if (ranges.length > 0) {
        _ref1 = this.selections.slice(ranges.length);
        for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
          selection = _ref1[_j];
          selection.destroy();
        }
        this.selections = this.selections.slice(0, ranges.length);
        for (i = _k = 0, _len2 = ranges.length; _k < _len2; i = ++_k) {
          range = ranges[i];
          if (this.selections[i]) {
            this.selections[i].setBufferRange(range);
          } else {
            newSelection = this.editor.addSelectionForBufferRange(range);
            this.subscriptions.add(newSelection.cursor.onDidChangePosition((function(_this) {
              return function(event) {
                return _this.cursorMoved(event);
              };
            })(this)));
            this.subscriptions.add(newSelection.cursor.onDidDestroy((function(_this) {
              return function() {
                return _this.cursorDestroyed();
              };
            })(this)));
            this.selections.push(newSelection);
          }
        }
        markerSelected = true;
      }
      this.settingTabStop = false;
      return markerSelected;
    };

    SnippetExpansion.prototype.tabStopsForBufferPosition = function(bufferPosition) {
      return _.intersection(this.tabStopMarkers[this.tabStopIndex], this.editor.findMarkers({
        containsBufferPosition: bufferPosition
      }));
    };

    SnippetExpansion.prototype.destroy = function() {
      var marker, markers, _i, _j, _len, _len1, _ref;
      this.subscriptions.dispose();
      _ref = this.tabStopMarkers;
      for (_i = 0, _len = _ref.length; _i < _len; _i++) {
        markers = _ref[_i];
        for (_j = 0, _len1 = markers.length; _j < _len1; _j++) {
          marker = markers[_j];
          marker.destroy();
        }
      }
      this.tabStopMarkers = [];
      return this.snippets.clearExpansions(this.editor);
    };

    SnippetExpansion.prototype.restore = function(editor) {
      this.editor = editor;
      return this.snippets.addExpansion(this.editor, this);
    };

    return SnippetExpansion;

  })();

}).call(this);
