import json

from endpoints.api import format_date

from abc import ABCMeta, abstractmethod
from collections import namedtuple
from six import add_metaclass

class Image(namedtuple('Image', ['docker_image_id', 'created', 'comment', 'command', 'image_size',
                                 'uploading', 'parents'])):
  """
  Image represents an image.
  :type name: string
  """

  def to_dict(self):
    image_data = {
      'id': self.docker_image_id,
      'created': format_date(self.created),
      'comment': self.comment,
      'command': json.loads(self.command) if self.command else None,
      'size': self.image_size,
      'uploading': self.uploading,
      'sort_index': len(self.parents),
    }

    # Calculate the ancestors string, with the DBID's replaced with the docker IDs.
    parent_docker_ids = [parent_image.docker_image_id for parent_image in self.parents]
    image_data['ancestors'] = '/{0}/'.format('/'.join(parent_docker_ids))

    return image_data

class ImageWithTags(namedtuple('ImageWithTags', ['image', 'tag_names'])):
  """
  ImageWithTags represents an image, along with the tags that point to it.
  :type image: Image
  :type tag_names: list of string
  """

  def to_dict(self):
    image_dict = self.image.to_dict()
    image_dict['tags'] = self.tag_names
    return image_dict


class ImageWithHistory(namedtuple('ImageWithHistory', ['image'])):
  """
  ImageWithHistory represents an image, along with its full parent image dictionaries.
  :type image: Image
  :type history: list of Image parents (name is old and must be kept for compat)
  """

  def to_dict(self):
    image_dict = self.image.to_dict()
    image_dict['history'] = [parent_image.to_dict() for parent_image in self.image.parents]
    return image_dict


@add_metaclass(ABCMeta)
class ImageInterface(object):
  """
  Interface that represents all data store interactions required by the image API endpoint.
  """

  @abstractmethod
  def get_repository_images(self, namespace_name, repo_name):
    """
    Returns an iterator of all the ImageWithTag's defined in the matching repository. If the
    repository doesn't exist, returns None.
    """

  @abstractmethod
  def get_repository_image(self, namespace_name, repo_name, docker_image_id):
    """
    Returns the matching ImageWithHistory under the matching repository, if any. If none,
    returns None.
    """