# Copyright 2016 Hardcoded Software (http://www.hardcoded.net)
#
# This software is licensed under the "GPLv3" License as described in the "LICENSE" file,
# which should be included with this package. The terms are also available at
# http://www.gnu.org/licenses/gpl-3.0.html

import logging
from hscommon.util import get_file_ext, format_size

from core.util import format_timestamp, format_perc, format_dupe_count
from core import fs
from . import exif

# This global value is set by the platform-specific subclasser of the Photo base class
PLAT_SPECIFIC_PHOTO_CLASS = None

def format_dimensions(dimensions):
    return '%d x %d' % (dimensions[0], dimensions[1])

def get_delta_dimensions(value, ref_value):
    return (value[0]-ref_value[0], value[1]-ref_value[1])


class Photo(fs.File):
    INITIAL_INFO = fs.File.INITIAL_INFO.copy()
    INITIAL_INFO.update({
        'dimensions': (0, 0),
        'exif_timestamp': '',
    })
    __slots__ = fs.File.__slots__ + tuple(INITIAL_INFO.keys())

    # These extensions are supported on all platforms
    HANDLED_EXTS = {'png', 'jpg', 'jpeg', 'gif', 'bmp', 'tiff', 'tif'}

    def _plat_get_dimensions(self):
        raise NotImplementedError()

    def _plat_get_blocks(self, block_count_per_side, orientation):
        raise NotImplementedError()

    def _get_orientation(self):
        if not hasattr(self, '_cached_orientation'):
            try:
                with self.path.open('rb') as fp:
                    exifdata = exif.get_fields(fp)
                    # the value is a list (probably one-sized) of ints
                    orientations = exifdata['Orientation']
                    self._cached_orientation = orientations[0]
            except Exception: # Couldn't read EXIF data, no transforms
                self._cached_orientation = 0
        return self._cached_orientation

    def _get_exif_timestamp(self):
        try:
            with self.path.open('rb') as fp:
                exifdata = exif.get_fields(fp)
                return exifdata['DateTimeOriginal']
        except Exception:
            logging.info("Couldn't read EXIF of picture: %s", self.path)
        return ''

    @classmethod
    def can_handle(cls, path):
        return fs.File.can_handle(path) and get_file_ext(path.name) in cls.HANDLED_EXTS

    def get_display_info(self, group, delta):
        size = self.size
        mtime = self.mtime
        dimensions = self.dimensions
        m = group.get_match_of(self)
        if m:
            percentage = m.percentage
            dupe_count = 0
            if delta:
                r = group.ref
                size -= r.size
                mtime -= r.mtime
                dimensions = get_delta_dimensions(dimensions, r.dimensions)
        else:
            percentage = group.percentage
            dupe_count = len(group.dupes)
        dupe_folder_path = getattr(self, 'display_folder_path', self.folder_path)
        return {
            'name': self.name,
            'folder_path': str(dupe_folder_path),
            'size': format_size(size, 0, 1, False),
            'extension': self.extension,
            'dimensions': format_dimensions(dimensions),
            'exif_timestamp': self.exif_timestamp,
            'mtime': format_timestamp(mtime, delta and m),
            'percentage': format_perc(percentage),
            'dupe_count': format_dupe_count(dupe_count),
        }

    def _read_info(self, field):
        fs.File._read_info(self, field)
        if field == 'dimensions':
            self.dimensions = self._plat_get_dimensions()
            if self._get_orientation() in {5, 6, 7, 8}:
                self.dimensions = (self.dimensions[1], self.dimensions[0])
        elif field == 'exif_timestamp':
            self.exif_timestamp = self._get_exif_timestamp()

    def get_blocks(self, block_count_per_side):
        return self._plat_get_blocks(block_count_per_side, self._get_orientation())

