function SetupCtrl($scope, $timeout, ApiService, Features, UserService, ContainerService, CoreDialog) {
  if (!Features.SUPER_USERS) {
    return;
  }

  $scope.HOSTNAME_REGEX = '^[a-zA-Z-0-9\.]+(:[0-9]+)?$';

  $scope.validateHostname = function(hostname) {
    if (hostname.indexOf('127.0.0.1') == 0 || hostname.indexOf('localhost') == 0) {
      return 'Please specify a non-localhost hostname. "localhost" will refer to the container, not your machine.'
    }

    return null;
  };

  // Note: The values of the enumeration are important for isStepFamily. For example,
  // *all* states under the "configuring db" family must start with "config-db".
  $scope.States = {
    // Loading the state of the product.
    'LOADING': 'loading',

    // The configuration directory is missing.
    'MISSING_CONFIG_DIR': 'missing-config-dir',

    // The config.yaml exists but it is invalid.
    'INVALID_CONFIG': 'config-invalid',

    // DB is being configured.
    'CONFIG_DB': 'config-db',

    // DB information is being validated.
    'VALIDATING_DB': 'config-db-validating',

    // DB information is being saved to the config.
    'SAVING_DB': 'config-db-saving',

    // A validation error occurred with the database.
    'DB_ERROR': 'config-db-error',

    // Database is being setup.
    'DB_SETUP': 'setup-db',

    // Database setup has succeeded.
    'DB_SETUP_SUCCESS': 'setup-db-success',

    // An error occurred when setting up the database.
    'DB_SETUP_ERROR': 'setup-db-error',

    // The container is being restarted for the database changes.
    'DB_RESTARTING': 'setup-db-restarting',

    // A superuser is being configured.
    'CREATE_SUPERUSER': 'create-superuser',

    // The superuser is being created.
    'CREATING_SUPERUSER': 'create-superuser-creating',

    // An error occurred when setting up the superuser.
    'SUPERUSER_ERROR': 'create-superuser-error',

    // The superuser was created successfully.
    'SUPERUSER_CREATED': 'create-superuser-created',

    // General configuration is being setup.
    'CONFIG': 'config',

    // The configuration is fully valid.
    'VALID_CONFIG': 'valid-config',

    // The container is being restarted for the configuration changes.
    'CONFIG_RESTARTING': 'config-restarting',

    // The product is ready for use.
    'READY': 'ready'
  }

  $scope.csrf_token = window.__token;
  $scope.currentStep = $scope.States.LOADING;
  $scope.errors = {};
  $scope.stepProgress = [];
  $scope.hasSSL = false;
  $scope.hostname = null;

  $scope.$watch('currentStep', function(currentStep) {
    $scope.stepProgress = $scope.getProgress(currentStep);

    switch (currentStep) {
      case $scope.States.CONFIG:
        $('#setupModal').modal('hide');
        break;

      case $scope.States.MISSING_CONFIG_DIR:
        $scope.showMissingConfigDialog();
        break;

      case $scope.States.INVALID_CONFIG:
        $scope.showInvalidConfigDialog();
        break;

      case $scope.States.DB_SETUP:
        $scope.performDatabaseSetup();
        // Fall-through.

      case $scope.States.CREATE_SUPERUSER:
      case $scope.States.DB_RESTARTING:
      case $scope.States.CONFIG_DB:
      case $scope.States.VALID_CONFIG:
      case $scope.States.READY:
        $('#setupModal').modal({
            keyboard: false,
            backdrop: 'static'
        });
        break;
    }
  });

  $scope.restartContainer = function(state) {
    $scope.currentStep = state;
    ContainerService.restartContainer(function() {
      $scope.checkStatus()
    });
  };

  $scope.showSuperuserPanel = function() {
    $('#setupModal').modal('hide');
    var prefix = $scope.hasSSL ? 'https' : 'http';
    var hostname = $scope.hostname;
    window.location = prefix + '://' + hostname + '/superuser';
  };

  $scope.configurationSaved = function(config) {
    $scope.hasSSL = config['PREFERRED_URL_SCHEME'] == 'https';
    $scope.hostname = config['SERVER_HOSTNAME'];
    $scope.currentStep = $scope.States.VALID_CONFIG;
  };

  $scope.getProgress = function(step) {
    var isStep = $scope.isStep;
    var isStepFamily = $scope.isStepFamily;
    var States = $scope.States;

    return [
      isStepFamily(step, States.CONFIG_DB),
      isStepFamily(step, States.DB_SETUP),
      isStep(step, States.DB_RESTARTING),
      isStepFamily(step, States.CREATE_SUPERUSER),
      isStep(step, States.CONFIG),
      isStep(step, States.VALID_CONFIG),
      isStep(step, States.CONFIG_RESTARTING),
      isStep(step, States.READY)
    ];
  };

  $scope.isStepFamily = function(step, family) {
    if (!step) { return false; }
    return step.indexOf(family) == 0;
  };

  $scope.isStep = function(step) {
    for (var i = 1; i < arguments.length; ++i) {
      if (arguments[i] == step) {
        return true;
      }
    }
    return false;
  };

  $scope.showInvalidConfigDialog = function() {
    var message = "The <code>config.yaml</code> file found in <code>conf/stack</code> could not be parsed."
    var title = "Invalid configuration file";
    CoreDialog.fatal(title, message);
  };


  $scope.showMissingConfigDialog = function() {
    var message = "A volume should be mounted into the container at <code>/conf/stack</code>: " +
                  "<br><br><pre>docker run -v /path/to/config:/conf/stack</pre>" +
                  "<br>Once fixed, restart the container. For more information, " +
                  "<a href='https://coreos.com/docs/enterprise-registry/initial-setup/'>" +
                  "Read the Setup Guide</a>"

    var title = "Missing configuration volume";
    CoreDialog.fatal(title, message);
  };

  $scope.parseDbUri = function(value) {
    if (!value) { return null; }

    // Format: mysql+pymysql://<username>:<url escaped password>@<hostname>/<database_name>
    var uri = URI(value);
    return {
      'kind': uri.protocol(),
      'username': uri.username(),
      'password': uri.password(),
      'server': uri.host(),
      'database': uri.path() ? uri.path().substr(1) : ''
    };
  };

  $scope.serializeDbUri = function(fields) {
    if (!fields['server']) { return ''; }

    try {
      if (!fields['server']) { return ''; }
      if (!fields['database']) { return ''; }

      var uri = URI();
      uri = uri && uri.host(fields['server']);
      uri = uri && uri.protocol(fields['kind']);
      uri = uri && uri.username(fields['username']);
      uri = uri && uri.password(fields['password']);
      uri = uri && uri.path('/' + (fields['database'] || ''));
      uri = uri && uri.toString();
    } catch (ex) {
      return '';
    }

    return uri;
  };

  $scope.createSuperUser = function() {
    $scope.currentStep = $scope.States.CREATING_SUPERUSER;
    ApiService.scCreateInitialSuperuser($scope.superUser, null).then(function(resp) {
      UserService.load();
      $scope.checkStatus();
    }, function(resp) {
      $scope.currentStep = $scope.States.SUPERUSER_ERROR;
      $scope.errors.SuperuserCreationError = ApiService.getErrorMessage(resp, 'Could not create superuser');
    });
  };

  $scope.performDatabaseSetup = function() {
    $scope.currentStep = $scope.States.DB_SETUP;
    ApiService.scSetupDatabase(null, null).then(function(resp) {
      if (resp['error']) {
        $scope.currentStep = $scope.States.DB_SETUP_ERROR;
        $scope.errors.DatabaseSetupError = resp['error'];
      } else {
        $scope.currentStep = $scope.States.DB_SETUP_SUCCESS;
      }
    }, ApiService.errorDisplay('Could not setup database. Please report this to support.'))
  };

  $scope.validateDatabase = function() {
    $scope.currentStep = $scope.States.VALIDATING_DB;
    $scope.databaseInvalid = null;

    var data = {
      'config': {
        'DB_URI': $scope.databaseUri
      },
      'hostname': window.location.host
    };

    var params = {
      'service': 'database'
    };

    ApiService.scValidateConfig(data, params).then(function(resp) {
      var status = resp.status;

      if (status) {
        $scope.currentStep = $scope.States.SAVING_DB;
        ApiService.scUpdateConfig(data, null).then(function(resp) {
          $scope.checkStatus();
        }, ApiService.errorDisplay('Cannot update config. Please report this to support'));
      } else {
        $scope.currentStep = $scope.States.DB_ERROR;
        $scope.errors.DatabaseValidationError = resp.reason;
      }
    }, ApiService.errorDisplay('Cannot validate database. Please report this to support'));
  };

  $scope.checkStatus = function() {
    ContainerService.checkStatus(function(resp) {
      $scope.currentStep = resp['status'];
    }, $scope.hasSSL);
  };

  // Load the initial status.
  $scope.checkStatus();
}