(function() {
  var BufferPatch, Marker, MarkerPatch, Serializable, Transaction, find,
    __hasProp = {}.hasOwnProperty,
    __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };

  find = require('underscore-plus').find;

  Serializable = require('serializable');

  BufferPatch = require('./buffer-patch');

  MarkerPatch = require('./marker-patch');

  Marker = require('./marker');

  module.exports = Transaction = (function(_super) {
    __extends(Transaction, _super);

    Transaction.registerDeserializers(BufferPatch, MarkerPatch);

    function Transaction(patches, groupingInterval, oldMarkersSnapshot, newMarkersSnapshot) {
      this.patches = patches;
      if (groupingInterval == null) {
        groupingInterval = 0;
      }
      this.oldMarkersSnapshot = oldMarkersSnapshot;
      this.newMarkersSnapshot = newMarkersSnapshot;
      this.groupingExpirationTime = Date.now() + groupingInterval;
    }

    Transaction.prototype.serializeParams = function() {
      return {
        patches: this.patches.map(function(patch) {
          return patch.serialize();
        }),
        oldMarkersSnapshot: (this.oldMarkersSnapshot != null ? Marker.serializeSnapshot(this.oldMarkersSnapshot) : void 0),
        newMarkersSnapshot: (this.newMarkersSnapshot != null ? Marker.serializeSnapshot(this.newMarkersSnapshot) : void 0)
      };
    };

    Transaction.prototype.deserializeParams = function(params) {
      params.patches = params.patches.map((function(_this) {
        return function(patchState) {
          return _this.constructor.deserialize(patchState);
        };
      })(this));
      params.oldMarkersSnapshot = Marker.deserializeSnapshot(params.oldMarkersSnapshot);
      params.newMarkersSnapshot = Marker.deserializeSnapshot(params.newMarkersSnapshot);
      return params;
    };

    Transaction.prototype.push = function(patch) {
      return this.patches.push(patch);
    };

    Transaction.prototype.invert = function(buffer) {
      var newMarkersSnapshot, oldMarkersSnapshot;
      newMarkersSnapshot = this.oldMarkersSnapshot;
      oldMarkersSnapshot = buffer.markers.buildSnapshot();
      return new this.constructor(this.patches.map(function(patch) {
        return patch.invert(buffer);
      }).reverse(), 0, oldMarkersSnapshot, newMarkersSnapshot);
    };

    Transaction.prototype.applyTo = function(buffer) {
      var patch, _i, _len, _ref;
      _ref = this.patches;
      for (_i = 0, _len = _ref.length; _i < _len; _i++) {
        patch = _ref[_i];
        patch.applyTo(buffer);
      }
      if (this.newMarkersSnapshot != null) {
        return buffer.markers.applySnapshot(this.newMarkersSnapshot);
      }
    };

    Transaction.prototype.hasBufferPatches = function() {
      return find(this.patches, function(patch) {
        return patch instanceof BufferPatch;
      });
    };

    Transaction.prototype.merge = function(patch) {
      var subpatch, _i, _len, _ref;
      if (patch instanceof Transaction) {
        _ref = patch.patches;
        for (_i = 0, _len = _ref.length; _i < _len; _i++) {
          subpatch = _ref[_i];
          this.push(subpatch);
        }
        return this.groupingExpirationTime = patch.groupingExpirationTime, patch;
      } else {
        return this.push(patch);
      }
    };

    Transaction.prototype.isOpenForGrouping = function() {
      return this.groupingExpirationTime > Date.now();
    };

    return Transaction;

  })(Serializable);

}).call(this);
