// Generated by CoffeeScript 1.10.0

/* jshint node:true */


/* jshint -W097 */

(function() {
  'use strict';
  var FtpClient, FtpConnectionError, FtpReconnectError, Promise, PromiseFtp, STATUSES, complexPassthroughMethods, otherPrototypeMethods, path, simplePassthroughMethods,
    slice = [].slice;

  FtpClient = require('@icetee/ftp');

  Promise = require('bluebird');

  path = require('path');

  FtpConnectionError = require('promise-ftp-common').FtpConnectionError;

  FtpReconnectError = require('promise-ftp-common').FtpReconnectError;

  STATUSES = require('promise-ftp-common').STATUSES;

  simplePassthroughMethods = ['ascii', 'binary', 'abort', 'delete', 'status', 'rename', 'listSafe', 'list', 'get', 'put', 'append', 'pwd', 'mkdir', 'rmdir', 'system', 'size', 'lastMod', 'restart'];

  complexPassthroughMethods = ['site', 'cwd', 'cdup'];

  otherPrototypeMethods = ['connect', 'reconnect', 'logout', 'end', 'destroy', 'getConnectionStatus'];

  PromiseFtp = (function() {
    var i, j, len, len1, methodList, methodName, ref;

    function PromiseFtp() {
      var _connect, autoReconnect, autoReconnectPromise, client, closeError, commonLogicFactory, connectOptions, connectionStatus, i, intendedCwd, j, lastError, len, len1, name, preserveCwd, promisifiedClientMethods, unexpectedClose;
      if (!(this instanceof PromiseFtp)) {
        throw new TypeError("PromiseFtp constructor called without 'new' keyword");
      }
      connectionStatus = STATUSES.NOT_YET_CONNECTED;
      client = new FtpClient();
      this.rawClient = client;
      connectOptions = null;
      autoReconnect = null;
      preserveCwd = null;
      intendedCwd = '.';
      lastError = null;
      closeError = null;
      unexpectedClose = null;
      autoReconnectPromise = null;
      promisifiedClientMethods = {};
      client.on('error', function(err) {
        return lastError = err;
      });
      client.on('close', function(hadError) {
        if (hadError) {
          closeError = lastError;
        }
        unexpectedClose = connectionStatus !== STATUSES.DISCONNECTING && connectionStatus !== STATUSES.LOGGING_OUT;
        connectionStatus = STATUSES.DISCONNECTED;
        return autoReconnectPromise = null;
      });
      _connect = function(tempStatus) {
        return new Promise(function(resolve, reject) {
          var onError, onReady, serverMessage;
          connectionStatus = tempStatus;
          serverMessage = null;
          client.once('greeting', function(msg) {
            return serverMessage = msg;
          });
          onReady = function() {
            client.removeListener('error', onError);
            connectionStatus = STATUSES.CONNECTED;
            closeError = null;
            unexpectedClose = false;
            return resolve(serverMessage);
          };
          onError = function(err) {
            client.removeListener('ready', onReady);
            return reject(err);
          };
          client.once('ready', onReady);
          client.once('error', onError);
          return client.connect(connectOptions);
        });
      };
      this.connect = function(options) {
        return Promise["try"](function() {
          var key, ref, value;
          if (connectionStatus !== STATUSES.NOT_YET_CONNECTED && connectionStatus !== STATUSES.DISCONNECTED) {
            throw new FtpConnectionError("can't connect when connection status is: '" + connectionStatus + "'");
          }
          connectOptions = {};
          for (key in options) {
            value = options[key];
            connectOptions[key] = value;
          }
          if (options.secureOptions) {
            connectOptions.secureOptions = {};
            ref = options.secureOptions;
            for (key in ref) {
              value = ref[key];
              connectOptions.secureOptions[key] = value;
            }
          }
          autoReconnect = !!options.autoReconnect;
          delete connectOptions.autoReconnect;
          preserveCwd = !!options.preserveCwd;
          delete connectOptions.preserveCwd;
          return _connect(STATUSES.CONNECTING);
        });
      };
      this.reconnect = function() {
        return Promise["try"](function() {
          if (connectionStatus !== STATUSES.NOT_YET_CONNECTED && connectionStatus !== STATUSES.DISCONNECTED) {
            throw new FtpConnectionError("can't reconnect when connection status is: '" + connectionStatus + "'");
          }
          return _connect(STATUSES.RECONNECTING);
        });
      };
      this.logout = function() {
        var wait;
        wait = autoReconnectPromise ? autoReconnectPromise : Promise.resolve();
        return wait.then(function() {
          if (connectionStatus === STATUSES.NOT_YET_CONNECTED || connectionStatus === STATUSES.DISCONNECTED || connectionStatus === STATUSES.DISCONNECTING) {
            throw new FtpConnectionError("can't log out when connection status is: " + connectionStatus);
          }
          connectionStatus = STATUSES.LOGGING_OUT;
          return promisifiedClientMethods.logout();
        });
      };
      this.end = function() {
        return new Promise(function(resolve, reject) {
          if (connectionStatus === STATUSES.NOT_YET_CONNECTED || connectionStatus === STATUSES.DISCONNECTED) {
            return reject(new FtpConnectionError("can't end connection when connection status is: " + connectionStatus));
          }
          connectionStatus = STATUSES.DISCONNECTING;
          client.once('close', function(hadError) {
            return resolve(hadError ? lastError || true : false);
          });
          return client.end();
        });
      };
      this.destroy = function() {
        var wasDisconnected;
        if (connectionStatus === STATUSES.NOT_YET_CONNECTED || connectionStatus === STATUSES.DISCONNECTED) {
          wasDisconnected = true;
        } else {
          wasDisconnected = false;
          connectionStatus = STATUSES.DISCONNECTING;
        }
        client.destroy();
        return wasDisconnected;
      };
      this.getConnectionStatus = function() {
        return connectionStatus;
      };
      this.site = function(command) {
        return promisifiedClientMethods.site(command).then(function(result) {
          return {
            text: result[0],
            code: result[1]
          };
        });
      };
      this.cwd = function(dir) {
        return promisifiedClientMethods.cwd(dir).then(function(result) {
          if (dir.charAt(0) === '/') {
            intendedCwd = path.normalize(dir);
          } else {
            intendedCwd = path.join(intendedCwd, dir);
          }
          return result;
        });
      };
      this.cdup = function() {
        return promisifiedClientMethods.cdup().then(function(result) {
          intendedCwd = path.join(intendedCwd, '..');
          return result;
        });
      };
      commonLogicFactory = function(name, handler) {
        promisifiedClientMethods[name] = function() {
          var args;
          args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
          return new Promise(function(resolve, reject) {
            var onError;
            onError = function(err) {
              return reject(err);
            };
            client.once('error', onError);
            return client[name].apply(client, slice.call(args).concat([function(err, res) {
              client.removeListener('error', onError);
              if (err) {
                return reject(err);
              } else {
                return resolve(res);
              }
            }]));
          });
        };
        if (!handler) {
          handler = promisifiedClientMethods[name];
        }
        return function() {
          var args;
          args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
          return Promise["try"]((function(_this) {
            return function() {
              if (unexpectedClose && autoReconnect && !autoReconnectPromise) {
                autoReconnectPromise = _connect(STATUSES.RECONNECTING)["catch"](function(err) {
                  throw new FtpReconnectError(closeError, err, false);
                }).then(function() {
                  if (preserveCwd) {
                    return promisifiedClientMethods.cwd(intendedCwd)["catch"]((function(_this) {
                      return function(err) {
                        _this.destroy();
                        throw new FtpReconnectError(closeError, err, true);
                      };
                    })(this));
                  } else {
                    return intendedCwd = '.';
                  }
                });
              }
              if (autoReconnectPromise) {
                return autoReconnectPromise;
              } else if (connectionStatus !== STATUSES.CONNECTED) {
                throw new FtpConnectionError("can't perform '" + name + "' command when connection status is: " + connectionStatus);
              }
            };
          })(this)).then(function() {
            return handler.apply(null, args);
          });
        };
      };
      for (i = 0, len = simplePassthroughMethods.length; i < len; i++) {
        name = simplePassthroughMethods[i];
        this[name] = commonLogicFactory(name);
      }
      for (j = 0, len1 = complexPassthroughMethods.length; j < len1; j++) {
        name = complexPassthroughMethods[j];
        this[name] = commonLogicFactory(name, this[name]);
      }
    }

    ref = [simplePassthroughMethods, complexPassthroughMethods, otherPrototypeMethods];
    for (i = 0, len = ref.length; i < len; i++) {
      methodList = ref[i];
      for (j = 0, len1 = methodList.length; j < len1; j++) {
        methodName = methodList[j];
        PromiseFtp.prototype[methodName] = null;
      }
    }

    return PromiseFtp;

  })();

  module.exports = PromiseFtp;

}).call(this);
