# Copyright 2011 Google Inc. All Rights Reserved.
"""Compute image checksum."""

from __future__ import print_function

import os
import threading

from cros_utils import logger
from cros_utils.file_utils import FileUtils


class ImageChecksummer(object):
  """Compute image checksum."""

  class PerImageChecksummer(object):
    """Compute checksum for an image."""

    def __init__(self, label, log_level):
      self._lock = threading.Lock()
      self.label = label
      self._checksum = None
      self.log_level = log_level

    def Checksum(self):
      with self._lock:
        if not self._checksum:
          logger.GetLogger().LogOutput(
              "Acquiring checksum for '%s'." % self.label.name)
          self._checksum = None
          if self.label.image_type != 'local':
            raise RuntimeError('Called Checksum on non-local image!')
          if self.label.chromeos_image:
            if os.path.exists(self.label.chromeos_image):
              self._checksum = FileUtils().Md5File(
                  self.label.chromeos_image, log_level=self.log_level)
              logger.GetLogger().LogOutput('Computed checksum is '
                                           ': %s' % self._checksum)
          if not self._checksum:
            raise RuntimeError('Checksum computing error.')
          logger.GetLogger().LogOutput('Checksum is: %s' % self._checksum)
        return self._checksum

  _instance = None
  _lock = threading.Lock()
  _per_image_checksummers = {}

  def __new__(cls, *args, **kwargs):
    with cls._lock:
      if not cls._instance:
        cls._instance = super(ImageChecksummer, cls).__new__(
            cls, *args, **kwargs)
      return cls._instance

  def Checksum(self, label, log_level):
    if label.image_type != 'local':
      raise RuntimeError('Attempt to call Checksum on non-local image.')
    with self._lock:
      if label.name not in self._per_image_checksummers:
        self._per_image_checksummers[label.name] = (
            ImageChecksummer.PerImageChecksummer(label, log_level))
      checksummer = self._per_image_checksummers[label.name]

    try:
      return checksummer.Checksum()
    except:
      logger.GetLogger().LogError('Could not compute checksum of image in label'
                                  " '%s'." % label.name)
      raise