// Generated by CoffeeScript 1.12.7
var Promise, dockerUtils, formatImageName, getBuilderLogPushEndpoint, getBuilderPushEndpoint, getBundleInfo, parseInput, performUpload, showPushProgress, uploadLogs, uploadToPromise;

Promise = require('bluebird');

dockerUtils = require('../utils/docker');

getBuilderPushEndpoint = function(baseUrl, owner, app) {
  var args, querystring;
  querystring = require('querystring');
  args = querystring.stringify({
    owner: owner,
    app: app
  });
  return "https://builder." + baseUrl + "/v1/push?" + args;
};

getBuilderLogPushEndpoint = function(baseUrl, buildId, owner, app) {
  var args, querystring;
  querystring = require('querystring');
  args = querystring.stringify({
    owner: owner,
    app: app,
    buildId: buildId
  });
  return "https://builder." + baseUrl + "/v1/pushLogs?" + args;
};

formatImageName = function(image) {
  return image.split('/').pop();
};

parseInput = Promise.method(function(params, options) {
  var appName, image, source;
  if (params.appName == null) {
    throw new Error('Need an application to deploy to!');
  }
  appName = params.appName;
  image = void 0;
  if (params.image != null) {
    if (options.build || (options.source != null)) {
      throw new Error('Build and source parameters are not applicable when specifying an image');
    }
    options.build = false;
    image = params.image;
  } else if (options.build) {
    source = options.source || '.';
  } else {
    throw new Error('Need either an image or a build flag!');
  }
  return [appName, options.build, source, image];
});

showPushProgress = function(message) {
  var progressBar, visuals;
  visuals = require('resin-cli-visuals');
  progressBar = new visuals.Progress(message);
  progressBar.update({
    percentage: 0
  });
  return progressBar;
};

getBundleInfo = function(options) {
  var helpers;
  helpers = require('../utils/helpers');
  return helpers.getAppInfo(options.appName).then(function(app) {
    return [app.arch, app.device_type];
  });
};

performUpload = function(imageStream, token, username, url, appName, logger) {
  var progressBar, progressMessage, progressStream, request, streamWithProgress, uploadRequest, zlib;
  request = require('request');
  progressStream = require('progress-stream');
  zlib = require('zlib');
  progressMessage = logger.formatMessage('info', 'Deploying').slice(0, -1);
  progressBar = showPushProgress(progressMessage);
  streamWithProgress = imageStream.pipe(progressStream({
    time: 500,
    length: imageStream.length
  }, function(arg) {
    var eta, percentage;
    percentage = arg.percentage, eta = arg.eta;
    return progressBar.update({
      percentage: Math.min(percentage, 100),
      eta: eta
    });
  }));
  uploadRequest = request.post({
    url: getBuilderPushEndpoint(url, username, appName),
    headers: {
      'Content-Encoding': 'gzip'
    },
    auth: {
      bearer: token
    },
    body: streamWithProgress.pipe(zlib.createGzip({
      level: 6
    }))
  });
  return uploadToPromise(uploadRequest, logger);
};

uploadLogs = function(logs, token, url, buildId, username, appName) {
  var request;
  request = require('request');
  return request.post({
    json: true,
    url: getBuilderLogPushEndpoint(url, buildId, username, appName),
    auth: {
      bearer: token
    },
    body: Buffer.from(logs)
  });
};

uploadToPromise = function(uploadRequest, logger) {
  return new Promise(function(resolve, reject) {
    var handleMessage;
    handleMessage = function(data) {
      var e, obj;
      data = data.toString();
      logger.logDebug("Received data: " + data);
      try {
        obj = JSON.parse(data);
      } catch (error) {
        e = error;
        logger.logError('Error parsing reply from remote side');
        reject(e);
        return;
      }
      if (obj.type != null) {
        switch (obj.type) {
          case 'error':
            return reject(new Error("Remote error: " + obj.error));
          case 'success':
            return resolve(obj);
          case 'status':
            return logger.logInfo("Remote: " + obj.message);
          default:
            return reject(new Error("Received unexpected reply from remote: " + data));
        }
      } else {
        return reject(new Error("Received unexpected reply from remote: " + data));
      }
    };
    return uploadRequest.on('error', reject).on('data', handleMessage);
  });
};

module.exports = {
  signature: 'deploy <appName> [image]',
  description: 'Deploy an image to a resin.io application',
  help: 'Use this command to deploy an image to an application, optionally building it first.\n\nUsage: deploy <appName> ([image] | --build [--source build-dir])\n\nNote: If building with this command, all options supported by `resin build`\nare also supported with this command.\n\nExamples:\n	$ resin deploy myApp --build --source myBuildDir/\n	$ resin deploy myApp myApp/myImage',
  permission: 'user',
  options: dockerUtils.appendOptions([
    {
      signature: 'build',
      boolean: true,
      description: 'Build image then deploy',
      alias: 'b'
    }, {
      signature: 'source',
      parameter: 'source',
      description: 'The source directory to use when building the image',
      alias: 's'
    }, {
      signature: 'nologupload',
      description: "Don't upload build logs to the dashboard with image (if building)",
      boolean: true
    }
  ]),
  action: function(params, options, done) {
    var Logger, _, logger, logs, resin, tmp, tmpNameAsync, upload;
    _ = require('lodash');
    tmp = require('tmp');
    tmpNameAsync = Promise.promisify(tmp.tmpName);
    resin = require('resin-sdk-preconfigured');
    Logger = require('../utils/logger');
    logger = new Logger();
    tmp.setGracefulCleanup();
    logs = '';
    upload = function(token, username, url) {
      return dockerUtils.getDocker(options).then(function(docker) {
        return parseInput(params, options).then(function(arg) {
          var appName, build, imageName, source;
          appName = arg[0], build = arg[1], source = arg[2], imageName = arg[3];
          return tmpNameAsync().then(function(bufferFile) {
            options = _.assign({}, options, {
              appName: appName
            });
            params = _.assign({}, params, {
              source: source
            });
            return Promise["try"](function() {
              if (build) {
                return dockerUtils.runBuild(params, options, getBundleInfo, logger);
              } else {
                return {
                  image: imageName,
                  log: ''
                };
              }
            }).then(function(arg1) {
              var buildLogs, imageName;
              imageName = arg1.image, buildLogs = arg1.log;
              logger.logInfo('Initializing deploy...');
              logs = buildLogs;
              return Promise.all([dockerUtils.bufferImage(docker, imageName, bufferFile), token, username, url, params.appName, logger]).spread(performUpload);
            })["finally"](function() {
              return Promise["try"](function() {
                return require('mz/fs').unlink(bufferFile);
              })["catch"](_.noop);
            });
          });
        }).tap(function(arg) {
          var buildId, imageName;
          imageName = arg.image, buildId = arg.buildId;
          logger.logSuccess("Successfully deployed image: " + (formatImageName(imageName)));
          return buildId;
        }).then(function(arg) {
          var buildId, imageName;
          imageName = arg.image, buildId = arg.buildId;
          if (logs === '' || (options.nologupload != null)) {
            return '';
          }
          logger.logInfo('Uploading logs to dashboard...');
          return Promise.join(logs, token, url, buildId, username, params.appName, uploadLogs)["return"]('Successfully uploaded logs');
        }).then(function(msg) {
          if (msg !== '') {
            return logger.logSuccess(msg);
          }
        }).asCallback(done);
      });
    };
    return Promise.join(resin.auth.getToken(), resin.auth.whoami(), resin.settings.get('resinUrl'), upload);
  }
};