module.exports = function() {
  this.Before("@glacier", function (callback) {
    this.service = new this.AWS.Glacier.Client();
    callback();
  });

  this.Given(/^I have a Glacier vault$/, function(callback) {
    this.vaultName = 'aws-sdk-js-integration';
    var params = {vaultName: this.vaultName};
    this.request(null, 'createVault', params, callback, false);
  });

  this.Given(/^I upload a (\d+(?:\.\d+)?)MB Glacier archive to the vault( with (?:invalid|incorrect) checksum)?$/, function(size, invalid, callback) {
    var data = new Buffer(parseFloat(size) * 1024 * 1024);
    data.fill('0');
    var params = {vaultName: this.vaultName, body: data};
    if (invalid) {
      if (invalid.match("invalid")) params.checksum = '000';
      else params.checksum = '00000000000000000000000000000000';
    }
    this.request(null, 'uploadArchive', params, callback, false);
  });

  this.Then(/^the result should contain the Glacier archive ID$/, function(callback) {
    this.archiveId = this.data.archiveId;
    callback();
  });

  this.Then(/^the result should contain the same tree hash checksum$/, function(callback) {
    var hash = this.response.request.httpRequest.headers['x-amz-sha256-tree-hash'];
    this.assert.equal(this.data.checksum, hash);
    callback();
  });

  this.When(/^I describe the Glacier vault$/, function(callback) {
    var params = {vaultName: this.vaultName};
    this.request(null, 'describeVault', params, callback);
  });

  this.Then(/^I delete the Glacier archive$/, function(callback) {
    var params = {vaultName: this.vaultName, archiveId: this.archiveId};
    this.request(null, 'deleteArchive', params, callback);
  });

  this.Then(/^I delete the Glacier vault$/, function(callback) {
    var params = {vaultName: this.vaultName};
    this.eventually(callback, function(next) {
      this.request(null, 'deleteVault', params, next);
    });
  });

  this.When(/^I initiate a Glacier multi-part upload on a (\d+(?:\.\d+)?)MB archive in (\d+)MB chunks$/, function(totalSize, partSize, callback) {
    // setup multi-part upload
    this.uploadData = new Buffer(totalSize * 1024 * 1024);
    this.uploadData.fill('0');
    this.checksums = this.service.computeChecksums(this.uploadData);
    this.partCounter = 0;
    this.partSize = partSize * 1024 * 1024;

    var params = {vaultName: this.vaultName, partSize: this.partSize.toString()};
    this.request(null, 'initiateMultipartUpload', params, callback);
  });

  this.Then(/^the result should contain the Glacier multi-part upload ID$/, function(callback) {
    this.uploadId = this.data.uploadId;
    callback();
  });

  this.Then(/^I send the next part$/, function(callback) {
    var start = this.partCounter;
    var end = Math.min(start + this.partSize, this.uploadData.length);
    var buf = this.uploadData.slice(start, end);
    var range = 'bytes ' + start + '-' + (end-1) + '/*';
    var params = {
      vaultName: this.vaultName,
      uploadId: this.uploadId,
      range: range,
      body: buf
    };
    this.request(null, 'uploadMultipartPart', params, callback);
    this.partCounter += this.partSize;
  });

  this.Then(/^I send the Glacier archive data in chunks$/, function(callback) {
    var numPartsLeft = Math.ceil(this.uploadData.length / this.partSize);
    for (var i = 0; i < this.uploadData.length; i += this.partSize) {
      var end = Math.min(i + this.partSize, this.uploadData.length);
      var buf = this.uploadData.slice(i, end);
      var range = 'bytes ' + i + '-' + (end-1) + '/*';
      var params = {
        vaultName: this.vaultName,
        uploadId: this.uploadId,
        range: range,
        body: buf
      };
      this.service.uploadMultipartPart(params, function() {
        if (--numPartsLeft == 0) callback();
      });
    }
  });

  this.Then(/^I complete the Glacier multi-part upload$/, function(callback) {
    var params = {
      vaultName: this.vaultName,
      uploadId: this.uploadId,
      archiveSize: this.uploadData.length.toString(),
      checksum: this.checksums.treeHash
    }
    this.request(null, 'completeMultipartUpload', params, callback);
  });

};
