/**
 * An element which displays the tags panel for a repository view.
 */
angular.module('quay').directive('repoPanelTags', function () {
  var directiveDefinitionObject = {
    priority: 0,
    templateUrl: '/static/directives/repo-view/repo-panel-tags.html',
    replace: false,
    transclude: false,
    restrict: 'C',
    scope: {
      'repository': '=repository',
      'selectedTags': '=selectedTags',
      'imagesResource': '=imagesResource',
      'images': '=images',

      'isEnabled': '=isEnabled',

      'getImages': '&getImages'
    },
    controller: function($scope, $element, $filter, $location, ApiService, UIService) {
      var orderBy = $filter('orderBy');

      $scope.checkedTags = UIService.createCheckStateController([], 'name');
      $scope.options = {
        'predicate': 'last_modified_datetime',
        'reverse': false,
        'page': 0
      };

      $scope.iterationState = {};
      $scope.tagHistory = {};
      $scope.tagActionHandler = null;
      $scope.showingHistory = false;

      var setTagState = function() {
        if (!$scope.repository || !$scope.selectedTags) { return; }

        var tags = [];
        var allTags = [];
        var imageMap = {};
        var imageTracks = [];

        // Build a list of tags and filtered tags.
        for (var tag in $scope.repository.tags) {
          if (!$scope.repository.tags.hasOwnProperty(tag)) { continue; }

          var tagData = $scope.repository.tags[tag];
          var tagInfo = $.extend(tagData, {
            'name': tag,
            'last_modified_datetime': (new Date(tagData.last_modified || 0)).valueOf() * (-1)
          });

          allTags.push(tagInfo);

          if (!$scope.options.tagFilter || tag.indexOf($scope.options.tagFilter) >= 0 ||
              tagInfo.image_id.indexOf($scope.options.tagFilter) >= 0) {
            tags.push(tagInfo);
          }
        }

        // Sort the tags by the predicate and the reverse, and map the information.
        var imageIDs = [];
        var ordered = orderBy(tags, $scope.options.predicate, $scope.options.reverse);
        var checked = [];

        for (var i = 0; i < ordered.length; ++i) {
          var tagInfo = ordered[i];
          if (!imageMap[tagInfo.image_id]) {
            imageMap[tagInfo.image_id] = [];
            imageIDs.push(tagInfo.image_id)
          }

          imageMap[tagInfo.image_id].push(tagInfo);

          if ($.inArray(tagInfo.name, $scope.selectedTags) >= 0) {
            checked.push(tagInfo);
          }
        };

        // Calculate the image tracks.
        var colors = d3.scale.category10();
        var index = 0;

        imageIDs.sort().map(function(image_id) {
          if (imageMap[image_id].length >= 2){
            imageTracks.push({
              'image_id': image_id,
              'color': colors(index),
              'count': imageMap[image_id].length,
              'tags': imageMap[image_id]
            });

            imageMap[image_id]['color'] = colors(index);

            ++index;
          }
        });

        $scope.imageMap = imageMap;
        $scope.imageTracks = imageTracks;

        $scope.tags = ordered;
        $scope.allTags = allTags;

        $scope.checkedTags = UIService.createCheckStateController(ordered, 'name', checked);
        $scope.checkedTags.listen(function(checked) {
          $scope.selectedTags = checked.map(function(tag_info) {
            return tag_info.name;
          });
        });
      }

      $scope.$watch('options.predicate', setTagState);
      $scope.$watch('options.reverse', setTagState);
      $scope.$watch('options.tagFilter', setTagState);

      $scope.$watch('selectedTags', function(selectedTags) {
        if (!selectedTags || !$scope.repository || !$scope.imageMap) { return; }

        $scope.checkedTags.setChecked(selectedTags.map(function(tag) {
          return $scope.repository.tags[tag];
        }));
      }, true);

      $scope.$watch('repository', function(repository) {
        if (!repository) { return; }

        // Process each of the tags.
        setTagState();
      });

      $scope.showHistory = function(value, opt_tagname) {
        $scope.options.historyFilter = opt_tagname ? opt_tagname : '';
        $scope.showingHistory = value;
      };

      $scope.toggleHistory = function() {
        $scope.showHistory(!$scope.showingHistory);
      };

      $scope.trackLineClass = function(index, track_info) {
        var startIndex = $.inArray(track_info.tags[0], $scope.tags);
        var endIndex = $.inArray(track_info.tags[track_info.tags.length - 1], $scope.tags);

        if (index == startIndex) {
          return 'start';
        }

        if (index == endIndex) {
          return 'end';
        }

        if (index > startIndex && index < endIndex) {
          return 'middle';
        }

        if (index < startIndex) {
          return 'before';
        }

        if (index > endIndex) {
          return 'after';
        }
      };

      $scope.tablePredicateClass = function(name, predicate, reverse) {
        if (name != predicate) {
          return '';
        }

        return 'current ' + (reverse ? 'reversed' : '');
      };

      $scope.askDeleteTag = function(tag) {
        $scope.tagActionHandler.askDeleteTag(tag);
      };

      $scope.askDeleteMultipleTags = function(tags) {
        if (tags.length == 1) {
          $scope.askDeleteTag(tags[0].name);
          return;
        }

        $scope.tagActionHandler.askDeleteMultipleTags(tags);
      };

      $scope.askAddTag = function(tag) {
        $scope.tagActionHandler.askAddTag(tag.image_id);
      };

      $scope.orderBy = function(predicate) {
        if (predicate == $scope.options.predicate) {
          $scope.options.reverse = !$scope.options.reverse;
          return;
        }

        $scope.options.reverse = false;
        $scope.options.predicate = predicate;
      };

      $scope.commitTagFilter = function(tag) {
        var r = new RegExp('^[0-9a-fA-F]{7}$');
        return tag.name.match(r);
      };

      $scope.allTagFilter = function(tag) {
        return true;
      };

      $scope.noTagFilter = function(tag) {
        return false;
      };

      $scope.imageIDFilter = function(image_id, tag) {
        return tag.image_id == image_id;
      };

      $scope.setTab = function(tab) {
        $location.search('tab', tab);
      };

      $scope.selectTrack = function(it) {
        $scope.checkedTags.checkByFilter(function(tag) {
          return $scope.imageIDFilter(it.image_id, tag);
        });
      };

      $scope.getTagNames = function(checked) {
        var names = checked.map(function(tag) {
          return tag.name;
        });

        return names.join(',');
      };

      $scope.loadTagHistory = function(tag) {
        delete $scope.tagHistory[tag.name];

        var params = {
          'repository': $scope.repository.namespace + '/' + $scope.repository.name,
          'specificTag': tag.name,
          'limit': 5
        };

        ApiService.listRepoTags(null, params).then(function(resp) {
          $scope.tagHistory[tag.name] = resp.tags;
        }, ApiService.errorDisplay('Could not load tag history'));
      };

      $scope.askRevertTag = function(tag, image_id) {
        $scope.tagActionHandler.askRevertTag(tag, image_id);
      };
    }
  };
  return directiveDefinitionObject;
});

