/**
 * An element which displays hosted Git (GitHub, Bitbucket)-specific setup information for its build triggers.
 */
angular.module('quay').directive('triggerSetupGithost', function () {
  var directiveDefinitionObject = {
    priority: 0,
    templateUrl: '/static/directives/trigger-setup-githost.html',
    replace: false,
    transclude: false,
    restrict: 'C',
    scope: {
      'repository': '=repository',
      'trigger': '=trigger',
      'kind': '@kind',

      'nextStepCounter': '=nextStepCounter',
      'currentStepValid': '=currentStepValid',

      'analyze': '&analyze'
    },
    controller: function($scope, $element, ApiService, TriggerService) {
      $scope.analyzeCounter = 0;
      $scope.setupReady = false;
      $scope.refs = null;
      $scope.branchNames = null;
      $scope.tagNames = null;

      $scope.state = {
        'currentRepo': null,
        'branchTagFilter': '',
        'hasBranchTagFilter': false,
        'isInvalidLocation': true,
        'currentLocation': null
      };

      var checkLocation = function() {
        var location = $scope.state.currentLocation || '';
        $scope.state.isInvalidLocation = $scope.supportsFullListing &&
                                         $scope.locations.indexOf(location) < 0;
      };

      $scope.isMatching = function(kind, name, filter) {
        try {
          var patt = new RegExp(filter);
        } catch (ex) {
          return false;
        }

        var fullname = (kind + '/' + name);
        var m = fullname.match(patt);
        return m && m[0].length == fullname.length;
      }

      $scope.addRef = function(kind, name) {
        if ($scope.isMatching(kind, name, $scope.state.branchTagFilter)) {
          return;
        }

        var newFilter = kind + '/' + name;
        var existing = $scope.state.branchTagFilter;
        if (existing) {
          $scope.state.branchTagFilter = '(' + existing + ')|(' + newFilter + ')';
        } else {
          $scope.state.branchTagFilter = newFilter;
        }
      }

      $scope.stepsCompleted = function() {
        $scope.analyze({'isValid': !$scope.state.isInvalidLocation});
      };

      $scope.loadRepositories = function(callback) {
        if (!$scope.trigger || !$scope.repository) { return; }

        var params = {
          'repository': $scope.repository.namespace + '/' + $scope.repository.name,
          'trigger_uuid': $scope.trigger.id
        };

        ApiService.listTriggerBuildSources(null, params).then(function(resp) {
          $scope.orgs = resp['sources'];
          setupTypeahead();
          callback();
        }, ApiService.errorDisplay('Cannot load repositories'));
      };

      $scope.loadBranchesAndTags = function(callback) {
        if (!$scope.trigger || !$scope.repository) { return; }

        var params = {
          'repository': $scope.repository.namespace + '/' + $scope.repository.name,
          'trigger_uuid': $scope.trigger['id'],
          'field_name': 'refs'
        };

        ApiService.listTriggerFieldValues($scope.trigger['config'], params).then(function(resp) {
          $scope.refs = resp['values'];
          $scope.branchNames = [];
          $scope.tagNames = [];

          for (var i = 0; i < $scope.refs.length; ++i) {
            var ref = $scope.refs[i];
            if (ref.kind == 'branch') {
              $scope.branchNames.push(ref.name);
            } else {
              $scope.tagNames.push(ref.name);
            }
          }

          callback();
        }, ApiService.errorDisplay('Cannot load branch and tag names'));
      };

      $scope.loadLocations = function(callback) {
        if (!$scope.trigger || !$scope.repository) { return; }

        $scope.locations = null;

        var params = {
          'repository': $scope.repository.namespace + '/' + $scope.repository.name,
          'trigger_uuid': $scope.trigger.id
        };

        ApiService.listBuildTriggerSubdirs($scope.trigger['config'], params).then(function(resp) {
          if (resp['status'] == 'error') {
            $scope.locations = [];
            callback(resp['message'] || 'Could not load Dockerfile locations');
            return;
          }

          $scope.locations = resp['subdir'] || [];

          // Select a default location (if any).
          if ($scope.locations.length > 0) {
            $scope.setLocation($scope.locations[0]);
          } else {
            $scope.state.currentLocation = null;
            $scope.trigger.$ready = true;
            checkLocation();
          }

          callback();
        }, ApiService.errorDisplay('Cannot load locations'));
      }

      $scope.handleLocationInput = function(location) {
        $scope.trigger['config']['subdir'] = location || '';
        $scope.trigger.$ready = true;
        checkLocation();
      };

      $scope.handleLocationSelected = function(datum) {
        $scope.setLocation(datum['value']);
      };

      $scope.setLocation = function(location) {
        $scope.state.currentLocation = location;
        $scope.trigger['config']['subdir'] = location || '';
        $scope.trigger.$ready = true;
        checkLocation();
      };

      $scope.selectRepo = function(repo, org) {
        $scope.state.currentRepo = {
          'repo': repo,
          'avatar_url': org['info']['avatar_url'],
          'toString': function() {
            return this.repo;
          }
        };
      };

      $scope.selectRepoInternal = function(currentRepo) {
        $scope.trigger.$ready = false;

        var params = {
          'repository': $scope.repository.namespace + '/' + $scope.repository.name,
          'trigger_uuid': $scope.trigger['id']
        };

        var repo = currentRepo['repo'];
        $scope.trigger['config'] = {
          'build_source': repo,
          'subdir': ''
        };
      };

      $scope.scmIcon = function(kind) {
        return TriggerService.getIcon(kind);
      };

      var setupTypeahead = function() {
        var repos = [];
        for (var i = 0; i < $scope.orgs.length; ++i) {
          var org = $scope.orgs[i];
          var orepos = org['repos'];
          for (var j = 0; j < orepos.length; ++j) {
            var repoValue = {
              'repo': orepos[j],
              'avatar_url': org['info']['avatar_url'],
              'toString': function() {
                return this.repo;
              }
            };
            var datum = {
              'name': orepos[j],
              'org': org,
              'value': orepos[j],
              'title': orepos[j],
              'item': repoValue
            };
            repos.push(datum);
          }
        }

        $scope.repoLookahead = repos;
      };

      $scope.$watch('trigger', function(trigger) {
        if (!trigger) { return; }
        $scope.supportsFullListing = TriggerService.supportsFullListing(trigger.service)
      });

      $scope.$watch('state.currentRepo', function(repo) {
        if (repo) {
          $scope.selectRepoInternal(repo);
        }
      });

      $scope.$watch('state.branchTagFilter', function(bf) {
        if (!$scope.trigger) { return; }

        if ($scope.state.hasBranchTagFilter) {
          $scope.trigger['config']['branchtag_regex'] = bf;
        } else {
          delete $scope.trigger['config']['branchtag_regex'];
        }
      });
    }
  };
  return directiveDefinitionObject;
});