# -*- coding: utf-8 -*-

# Copyright 2017 Mir Calculate. http://www.calculate-linux.org
#
#  Licensed under the Apache License, Version 2.0 (the "License");
#  you may not use this file except in compliance with the License.
#  You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
#  Unless required by applicable law or agreed to in writing, software
#  distributed under the License is distributed on an "AS IS" BASIS,
#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#  See the License for the specific language governing permissions and
#  limitations under the License.

import sys
import os
import re
from calculate.lib.cl_template import TemplateFormat
import hashlib

from calculate.lib.cl_lang import setLocalTranslate
from calculate.lib.utils.files import (getProgPath, pathJoin, process, STDOUT,
                                       readFile, writeFile, listDirectory)

_ = lambda x: x
setLocalTranslate('cl_ldap3', sys.modules[__name__])


class backgrounds(TemplateFormat):
    """
    Формат для модификации принадлежности файлов пакетам
    """
    text = ""
    source = None
    convert = None
    prefix = None
    stretch = False
    md5fn = "md5sum"

    def prepare(self):
        self.convert_cmd = getProgPath('/usr/bin/convert')
        self.identify_cmd = getProgPath('/usr/bin/identify')
        self.source_width = None
        self.source_height = None

    def textToXML(self):
        return self.text

    def setSource(self, source):
        self.source = source

    def setConvert(self, convert):
        self.convert = convert

    def setPrefix(self, prefix):
        self.prefix = prefix

    def getImageMD5(self, source):
        return hashlib.md5(readFile(source)).hexdigest()

    def setStretch(self, stretch):
        self.stretch = stretch

    def _create_image(self, source, target, width, height, force=False):
        res = "%dx%d" % (width, height)
        if not force and (
                width > self.source_width or height > self.source_height):
            return False
        convert = process(self.convert_cmd, "-quality", "95",
                          source, "-resize", "%s^" % res,
                          "-gravity", "center",
                          "-crop", "%s+0+0" % res,
                          target, stderr=STDOUT)
        convert.write(self.text)
        if convert.success():
            return True
        return False

    def get_image_resolution(self, source):
        identify = process(self.identify_cmd, "-format", "%[w] %[h]", source)
        if identify.success():
            swidth, _sep, sheight = identify.read().partition(" ")
            if swidth.isdigit() and sheight.isdigit():
                return int(swidth), int(sheight)
            return None, None

    def processingFile(self, textConfigFile, rootPath=None, nameFile=None):
        """Обработка конфигурационного файла"""
        if not (self.convert_cmd and self.identify_cmd):
            self.setError(_("Format 'backgrounds' is unavailable"))
            return False
        if not self.source:
            self.setError(_("format=backgrounds need 'link' parameter"))
            return False
        if not self.convert:
            self.convert = self.source.rpartition(".")[2].lower()
        if self.convert not in self.objVar.Get('cl_image_formats'):
            self.setError(_("Wrong image format '%s'") % self.convert)
            return False
        reRule = re.compile("^(\d+)x(\d+)$")
        if not rootPath:
            rootPath = '/'
        source = os.path.normpath(pathJoin(rootPath, self.source))
        if not os.path.exists(source):
            self.setError(_("File %s not found") % source)
            return False
        if self.prefix is None:
            workdir, prefix = os.path.split(nameFile)
        else:
            workdir = nameFile
            prefix = ""
        md5_fn = os.path.join(workdir, self.md5fn)
        image_md5 = self.getImageMD5(source)
        if os.path.exists(md5_fn):
            md5sum = readFile(md5_fn).strip()
            if md5sum == image_md5:
                return ""
        self.source_width, self.source_height = \
            self.get_image_resolution(source)
        if not self.source_width:
            self.setError(_("Failed to detect resolution for image '%s'") %
                          source)
            return False
        removed_files = []
        extensions = self.objVar.Get('cl_image_formats')
        re_remove = re.compile(r"^.*\d{3,4}x\d{3,4}\.(%s)$"
                               % "|".join(extensions))
        for remove_fn in listDirectory(workdir, fullPath=True):
            fn = os.path.split(remove_fn)[1]
            if re_remove.match(fn):
                removed_files.append(remove_fn)
        if self.text.strip():
            text_list = self.text.split("\n")
        else:
            text_list = self.objVar.Get('cl_resolutions')
        self.changed_files.append(md5_fn)
        image_files = []
        for line in (x for x in text_list if not x.startswith("#")):
            line = line.strip()
            if not line:
                continue
            rule_match = reRule.search(line)
            if not rule_match:
                self.setError(_("Wrong 'backgrounds' resolution: %s") % line)
                return False
            width, height = rule_match.groups()
            width = int(width)
            height = int(height)

            image_fn = pathJoin(workdir,
                                "%s%s.%s" % (prefix, line, self.convert))
            if self._create_image(source, image_fn, width, height,
                                  force=self.stretch):
                if image_fn in removed_files:
                    removed_files.remove(image_fn)
                image_files.append(image_fn)
            else:
                self.parent.printWARNING(
                    _("Failed to create image with %s resolution") % (
                        "%dx%d" % (width, height)))
        with writeFile(md5_fn) as f:
            f.write("%s\n" % image_md5)
        for remove_fn in removed_files:
            try:
                if os.path.lexists(remove_fn):
                    os.unlink(remove_fn)
            except (IOError, OSError):
                self.parent.printWARNING(_("Failed to remove %s") % remove_fn)
        self.changed_files.extend(image_files)
        self.changed_files.extend(removed_files)
        return ""
