.controller('openstackServerGroupInstanceSettingsCtrl', function(
    $scope,
    $controller,
    $uibModalStack,
    $state,
    imageReader,
  ) {
    function ensureCommandBackingDataFilteredExists() {
      if (!$scope.command.backingData) {
        $scope.command.backingData = { filtered: {} };
      } else if (!$scope.command.backingData.filtered) {
        $scope.command.backingData.filtered = {};
      }
    }

    function searchImages(q) {
      ensureCommandBackingDataFilteredExists();
      $scope.command.backingData.filtered.images = [
        {
          message: `<loading-spinner size="'nano'"></loading-spinner> Finding results matching "${q}"...`,
        },
      ];
      return Observable.fromPromise(
        imageReader.findImages({
          provider: $scope.command.selectedProvider,
          q: q,
          region: $scope.command.region,
          account: $scope.command.credentials,
        }),
      );
    }

    var imageSearchResultsStream = new Subject();

    imageSearchResultsStream
      .debounceTime(250)
      .switchMap(searchImages)
      .subscribe(function(data) {
        ensureCommandBackingDataFilteredExists();
        $scope.command.backingData.filtered.images = data;
        $scope.command.backingData.packageImages = $scope.command.backingData.filtered.images;
      });

    this.searchImages = function(q) {
      imageSearchResultsStream.next(q);
    };

    $scope.$watch('instanceSettings.$valid', function(newVal) {
      if (newVal) {
        ModalWizard.markClean('instance-settings');
        ModalWizard.markComplete('instance-settings');
      } else {
        ModalWizard.markIncomplete('instance-settings');
      }
    });
  });
  .controller('openstackServerGroupInstanceSettingsCtrl', function($scope, $controller, $uibModalStack, $state,
                                                          v2modalWizardService, imageReader) {

    function ensureCommandBackingDataFilteredExists() {
        if( !$scope.command.backingData ) {
          $scope.command.backingData = { filtered: {} };
        } else if( !$scope.command.backingData.filtered ) {
          $scope.command.backingData.filtered = {};
        }
    }

    function searchImages(q) {
      ensureCommandBackingDataFilteredExists();
      $scope.command.backingData.filtered.images = [
        {
          message: '<span class="glyphicon glyphicon-spinning glyphicon-asterisk"></span> Finding results matching "' + q + '"...'
        }
      ];
      return Observable.fromPromise(
        imageReader.findImages({
          provider: $scope.command.selectedProvider,
          q: q,
          region: $scope.command.region,
          account: $scope.command.credentials
        })
      );
    }

    var imageSearchResultsStream = new Subject();

    imageSearchResultsStream
      .debounceTime(250)
      .switchMap(searchImages)
      .subscribe(function (data) {
        ensureCommandBackingDataFilteredExists();
        $scope.command.backingData.filtered.images = data;
        $scope.command.backingData.packageImages = $scope.command.backingData.filtered.images;
      });

    this.searchImages = function(q) {
      imageSearchResultsStream.next(q);
    };

    $scope.$watch('instanceSettings.$valid', function(newVal) {
      if (newVal) {
        v2modalWizardService.markClean('instance-settings');
        v2modalWizardService.markComplete('instance-settings');
      } else {
        v2modalWizardService.markIncomplete('instance-settings');
      }
    });
  });
  .controller('dcosServerGroupContainerSettingsController', function($scope, dcosServerGroupConfigurationService) {
    this.groupByRegistry = function (image) {
      if (image) {
        if (image.fromContext) {
          return 'Find Image Result(s)';
        } else if (image.fromTrigger) {
          return 'Images from Trigger(s)';
        } else {
          return image.registry;
        }
      }
    };

    function searchImages(q) {
      return Observable.fromPromise(
        dcosServerGroupConfigurationService
          .configureCommand($scope.application, $scope.command, q)
      );
    }

    var imageSearchResultsStream = new Subject();

    imageSearchResultsStream
      .debounceTime(250)
      .switchMap(searchImages)
      .subscribe();

    this.searchImages = function(q) {
      imageSearchResultsStream.next(q);
    };

    this.isParametersValid = function(parameters) {
      return !(typeof parameters === 'string' || parameters instanceof String);
    };

    this.addParameter = function() {
      if (!this.isParametersValid($scope.command.docker.parameters)) {
        $scope.command.docker.parameters = [];
      }

      $scope.command.docker.parameters.push({
        key: '',
        value: ''
      });
    };

    this.removeParameter = function(index) {
      $scope.command.docker.parameters.splice(index, 1);
    };
  });
  .controller('awsServerGroupBasicSettingsCtrl', function($scope, $controller, $uibModalStack, $state,
                                                          v2modalWizardService, imageReader, namingService) {

    function searchImages(q) {
      $scope.command.backingData.filtered.images = [
        {
          message: '<span class="fa fa-cog fa-spin"></span> Finding results matching "' + q + '"...'
        }
      ];
      return Observable.fromPromise(
        imageReader.findImages({
          provider: $scope.command.selectedProvider,
          q: q,
          region: $scope.command.region
        })
      ).map(function (result) {
        if (result.length === 0 && q.startsWith('ami-') && q.length === 12) {
          // allow 'advanced' users to continue with just an ami id (backing image may not have been indexed yet)
          let record = {
            imageName: q,
            amis: {},
            attributes: {
              virtualizationType: '*',
            }
          };

          // trust that the specific image exists in the selected region
          record.amis[$scope.command.region] = [q];
          result = [record];
        }

        return result;
      });
    }

    var imageSearchResultsStream = new Subject();

    imageSearchResultsStream
      .debounceTime(250)
      .switchMap(searchImages)
      .subscribe(function (data) {
        $scope.command.backingData.filtered.images = data.map(function(image) {
          if (image.message && !image.imageName) {
            return image;
          }
          return {
            imageName: image.imageName,
            ami: image.amis && image.amis[$scope.command.region] ? image.amis[$scope.command.region][0] : null,
            virtualizationType: image.attributes ? image.attributes.virtualizationType : null,
          };
        });
        $scope.command.backingData.packageImages = $scope.command.backingData.filtered.images;
      });

    this.searchImages = function(q) {
      imageSearchResultsStream.next(q);
    };

    this.enableAllImageSearch = () => {
      $scope.command.viewState.useAllImageSelection = true;
      this.searchImages('');
    };

    this.imageChanged = (image) => {
      $scope.command.virtualizationType = image.virtualizationType;
    };

    angular.extend(this, $controller('BasicSettingsMixin', {
      $scope: $scope,
      imageReader: imageReader,
      namingService: namingService,
      $uibModalStack: $uibModalStack,
      $state: $state,
    }));

    $scope.$watch('form.$valid', function(newVal) {
      if (newVal) {
        v2modalWizardService.markClean('location');
        v2modalWizardService.markComplete('location');
      } else {
        v2modalWizardService.markIncomplete('location');
      }
    });

  });
  .controller('gceServerGroupBasicSettingsCtrl', function($scope, $controller, $uibModalStack, $state,
                                                          v2modalWizardService, imageReader, namingService) {

    function searchImages(q) {
      $scope.command.backingData.filtered.images = [
        {
          message: `<loading-spinner size="'nano'"></loading-spinner> Finding results matching "${q}"...`
        }
      ];
      return Observable.fromPromise(
        imageReader.findImages({
          provider: $scope.command.selectedProvider,
          q: q,
        })
      );
    }

    var imageSearchResultsStream = new Subject();

    imageSearchResultsStream
      .debounceTime(250)
      .switchMap(searchImages)
      .subscribe(function (data) {
        $scope.command.backingData.filtered.images = data.map(function(image) {
          if (image.message && !image.imageName) {
            return image;
          }
          return {
            account: image.account,
            imageName: image.imageName,
          };
        });
        $scope.command.backingData.packageImages = $scope.command.backingData.filtered.images;
      });

    this.searchImages = function(q) {
      imageSearchResultsStream.next(q);
    };

    this.enableAllImageSearch = () => {
      $scope.command.viewState.useAllImageSelection = true;
      this.searchImages('');
    };

    angular.extend(this, $controller('BasicSettingsMixin', {
      $scope: $scope,
      imageReader: imageReader,
      namingService: namingService,
      $uibModalStack: $uibModalStack,
      $state: $state,
    }));

    this.stackPattern = {
      test: function(stack) {
        var pattern = $scope.command.viewState.templatingEnabled ?
          /^([a-zA-Z0-9]*(\${.+})*)*$/ :
          /^[a-zA-Z0-9]*$/;
        return pattern.test(stack);
      }
    };

    this.detailPattern = {
      test: function(detail) {
        var pattern = $scope.command.viewState.templatingEnabled ?
          /^([a-zA-Z0-9-]*(\${.+})*)*$/ :
          /^[a-zA-Z0-9-]*$/;
        return pattern.test(detail);
      }
    };

    this.getSubnetPlaceholder = () => {
      if (!$scope.command.region) {
        return '(Select an account)';
      } else if ($scope.command.viewState.autoCreateSubnets) {
        return '(Subnet will be automatically selected)';
      } else if ($scope.command.viewState.autoCreateSubnets === null) {
        return '(Subnets not supported)';
      } else {
        return null;
      }
    };

  });
  .controller('dockerTriggerOptionsCtrl', function ($scope, dockerImageReader) {
    // These fields will be added to the trigger when the form is submitted
    this.command.extraFields = {};

    this.viewState = {
      tagsLoading: true,
      loadError: false,
      selectedTag: null,
    };

    let tagLoadSuccess = (tags) => {
      this.tags = tags;
      if (this.tags.length) {
        let defaultSelection = this.tags[0];
        this.viewState.selectedTag = defaultSelection;
        this.updateSelectedTag(defaultSelection);
      }
      this.viewState.tagsLoading = false;
    };

    let tagLoadFailure = () => {
      this.viewState.tagsLoading = false;
      this.viewState.loadError = true;
    };

    let initialize = () => {
      // cancel search stream if trigger has changed to some other type
      if (this.command.trigger.type !== 'docker') {
        subscription.unsubscribe();
        return;
      }
      this.searchTags();
    };

    let handleQuery = () => {
      return Observable.fromPromise(
        dockerImageReader.findTags({
          provider: 'dockerRegistry',
          account: this.command.trigger.account,
          repository: this.command.trigger.repository,
        }));
    };

    this.updateSelectedTag = (item) => {
      this.command.extraFields.tag = item;
    };

    let queryStream = new Subject();

    let subscription = queryStream
      .debounceTime(250)
      .switchMap(handleQuery)
      .subscribe(tagLoadSuccess, tagLoadFailure);

    this.searchTags = (query = '') => {
      this.tags = [`<span>Finding tags${query && ` matching ${query}`}...</span>`];
      queryStream.next();
    };

    $scope.$watch(() => this.command.trigger, initialize);
  });