/**
 * An element which displays its contents wrapped in an <a> tag, but only if the href is not null.
 */
angular.module('quay').directive('repoTagHistory', function () {
  var directiveDefinitionObject = {
    priority: 0,
    templateUrl: '/static/directives/repo-tag-history.html',
    replace: false,
    transclude: true,
    restrict: 'C',
    scope: {
      'repository': '=repository',
      'filter': '=filter',
      'isEnabled': '=isEnabled'
    },
    controller: function($scope, $element, ApiService) {
      $scope.tagHistoryData = null;
      $scope.tagHistoryLeaves = {};

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

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

        ApiService.listRepoTags(null, params).then(function(resp) {
          processTags(resp.tags);
        });
      };

      $scope.$watch('isEnabled', loadTimeline);
      $scope.$watch('repository', loadTimeline);

      var processTags = function(tags) {
        var entries = [];
        var tagEntries = {};

        // For each tag, turn the tag into create, move, delete, restore, etc entries.
        tags.forEach(function(tag) {
          var tagName = tag.name;
          var dockerImageId = tag.docker_image_id;

          if (!tagEntries[tagName]) {
            tagEntries[tagName] = [];
          }

          var removeEntry = function(entry) {
            entries.splice(entries.indexOf(entry), 1);
            tagEntries[entry.tag_name].splice(tagEntries[entry.tag_name].indexOf(entry), 1);
          };

          var addEntry = function(action, time, opt_docker_id, opt_old_docker_id) {
            var entry = {
              'tag_name': tagName,
              'action': action,
              'start_ts': tag.start_ts,
              'end_ts': tag.end_ts,
              'reversion': tag.reversion,
              'time': time * 1000, // JS expects ms, not s since epoch.
              'docker_image_id': opt_docker_id || dockerImageId,
              'old_docker_image_id': opt_old_docker_id || ''
            };

            tagEntries[tagName].push(entry);
            entries.push(entry);
          };

          // If the tag has an end time, it was either deleted or moved.
          if (tag.end_ts) {
            // If a future entry exists with a start time equal to the end time for this tag,
            // then the action was a move, rather than a delete and a create.
            var currentEntries = tagEntries[tagName];
            var futureEntry = currentEntries.length > 0 ? currentEntries[currentEntries.length - 1] : {};
            if (futureEntry.start_ts == tag.end_ts) {
              removeEntry(futureEntry);
              addEntry(futureEntry.reversion ? 'revert': 'move', tag.end_ts,
                       futureEntry.docker_image_id, dockerImageId);
            } else {
              addEntry('delete', tag.end_ts)
            }
          }

          // If the tag has a start time, it was created.
          if (tag.start_ts) {
            addEntry('create', tag.start_ts);
          }
        });

        // Sort the overall entries by datetime descending.
        entries.sort(function(a, b) {
          return b.time - a.time;
        });

        // Sort the tag entries by datetime descending.
        Object.keys(tagEntries).forEach(function(name) {
          var te = tagEntries[name];
          te.sort(function(a, b) {
            return b.time - a.time;
          });
        });

        // Add date dividers in.
        for (var i = entries.length - 1; i >= 1; --i) {
          var current = entries[i];
          var next = entries[i - 1];

          if (new Date(current.time).getDate() != new Date(next.time).getDate()) {
            entries.splice(i, 0, {
              'date_break': true,
              'date': new Date(current.time)
            });
            i--;
          }
        }

        // Add the top-level date divider.
        if (entries.length > 0) {
          entries.splice(0, 0, {
            'date_break': true,
            'date': new Date(entries[0].time)
          });
        }

        $scope.historyEntries = entries;
        $scope.historyEntryMap = tagEntries;
      };

      $scope.getEntryClasses = function(entry, historyFilter) {
        if (!entry.action) { return ''; }

        var classes = entry.action + ' ';
        if ($scope.historyEntryMap[entry.tag_name][0] == entry) {
          classes += ' current ';
        }

        if (!historyFilter || !entry.action) {
          return classes;
        }

        var parts = (historyFilter || '').split(',');
        var isMatch = parts.some(function(part) {
          if (part && entry.tag_name) {
            isMatch = entry.tag_name.indexOf(part) >= 0;
            isMatch = isMatch || entry.docker_image_id.indexOf(part) >= 0;
            isMatch = isMatch || entry.old_docker_image_id.indexOf(part) >= 0;
            return isMatch;
          }
        });

        classes += isMatch ? 'filtered-match' : 'filtered-mismatch';
        return classes;
      };
    }
  };
  return directiveDefinitionObject;
});