# encoding: utf-8
import os
import six

from typing import Optional
from PIL import Image, ImageOps
from commons.util import EscPosImage
from constants import ESC, GS


class LogoImage(object):
    def __init__(self):
        # type: () -> None
        self.data_dir = os.environ["HVDATADIR"]

    def get_logo(self):
        # type: () -> Image

        image_logo = self._logo_path()
        if image_logo is None:
            return ""

        base_width = 250
        with Image.open(image_logo) as image_opened:
            width_percent = (base_width / float(image_opened.size[0]))
            height_size = int((float(image_opened.size[1]) * float(width_percent)))
            with image_opened.resize((base_width, height_size)) as image_resize:
                with image_resize.convert("RGBA") as image_converted:
                    return self._image(image_converted, impl="bitImageColumn")

    def _logo_path(self):
        # type: () -> Optional[str]

        images_path = os.path.join(self.data_dir, "../../src/edpreports/src/static/logo_footer.png")
        if not os.path.exists(images_path):
            return None

        return images_path

    def _image(self, img_source, high_density_vertical=True, high_density_horizontal=True, impl="bitImageRaster"):
        im = EscPosImage(img_source)
        image_print = ""
        if impl == "bitImageRaster":
            # GS v 0, raster format bit image
            density_byte = (0 if high_density_horizontal else 1) + (0 if high_density_vertical else 2)
            header = GS + b"v0" + six.int2byte(density_byte) + self._int_low_high(im.width_bytes, 2) + self._int_low_high(
                im.height,
                2)
            image_print += (header + im.to_raster_format())
            return image_print

        if impl == "bitImageColumn":
            # ESC *, column format bit image
            density_byte = (1 if high_density_horizontal else 0) + (32 if high_density_vertical else 0)
            header = ESC + b"*" + six.int2byte(density_byte) + self._int_low_high(im.width, 2)
            outp = [ESC + b"3" + six.int2byte(48)]  # Adjust line-feed size
            for blob in im.to_column_format(high_density_vertical):
                outp.append(header + blob + b"\n")
            outp.append(ESC + b"2")  # Reset line-feed size
            return b''.join(outp)

    @staticmethod
    def _int_low_high(inp_number, out_bytes):
        """ Generate multiple bytes for a number: In lower and higher parts, or more parts as needed.

        :param inp_number: Input number
        :param out_bytes: The number of bytes to output (1 - 4).
        """
        max_input = (256 << (out_bytes * 8) - 1)
        if not 1 <= out_bytes <= 4:
            raise ValueError("Can only output 1-4 byes")
        if not 0 <= inp_number <= max_input:
            raise ValueError("Number too large. Can only output up to {0} in {1} byes".format(max_input, out_bytes))
        outp = b''
        for _ in range(0, out_bytes):
            outp += six.int2byte(inp_number % 256)
            inp_number //= 256
        return outp
