# encoding: utf-8

__all__ = ["StockImage", "StockImageException", "TK_IMAGE_FORMATS"]

import logging
import os
import tkinter as tk

logger = logging.getLogger(__name__)


class StockImageException(Exception):
    pass


BITMAP_TEMPLATE = "@{0}"
TK_BITMAP_FORMATS = [".xbm"]
TK_PHOTO_FORMATS = [".gif", ".pgm", ".ppm"]


if os.name == "nt":
    TK_BITMAP_FORMATS.append(".ico")
    BITMAP_TEMPLATE = "{0}"

if tk.TkVersion >= 8.6:
    TK_PHOTO_FORMATS.append(".png")


TK_IMAGE_FORMATS = TK_PHOTO_FORMATS + TK_BITMAP_FORMATS


_img_notsupported = """\
R0lGODlhZAAyAIQAAAAAAAsLCxMTExkZGSYmJicnJ11dXYGBgZubm5ycnJ2dnbGxsbOzs8TExMXF
xdXV1dbW1uTk5PLy8v39/f7+/v///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEK
AB8ALAAAAABkADIAAAX+4CeOZGmeaKqubOu+cCzPMmDfeK7vfO//QJ5rQCwaj8ikcslsOpUswGBC
qVqv2Kx2y+16v9nJAKAaFCiVtHrNbrvf8Lh83qYUBigplc7v+/9yFGJkJVJogIiJinAUYyaGi5GS
iI2EJJBuDQ0UChFqmmkNCAqHnAijFKKnnmoRpwgNoagVrqexFaBpEaS0qxWms26VjwOHbaeNDJ4Q
BwgVEAsICQ8SEg8Jp6QIBr5qEAG2z9HTEt+nCxAVCAfpEQzFEQ6nDhGcBga8wo6FxW/IAwISTCAA
rtEDQQMgQChmRR2CKmwWUqmS8FdCiRQenEEQgMCEBAKKIaNwKk1JRvv+LvVz8+/BA4//Qo5RWEyB
GZIBiKTzJmUAqYqNFPZMgObUQJcicw4AZ9IZSksjMB17mLCcw2QQHgigScGdSHYQJKyBIOABhHpA
L5Zt1vRZua8K2TqMM4yfMTb/dl5Ne3YaBAfawIr1tpKTg6wJIixMhW5umsUnIzt9U1fl3TUKSBXQ
m9lOOs+/7ihIY1Pn2DOYbz5DDeFMZm+uR1d4PVs25ZRRV9ZBcxeisd8QfzVkc3n4LzW8ewtPEzz4
bagipE6aTl0f9A/Sq2unXjm3cuTImxtfc2X58vLMxztHL9x3Q/bIcUfX3brU5tA+SRfRy/zOTdqd
+cdaEbYtBJSAaBj+6JMdRLi2H3HyYUcfOJ4EFYFfgHXFQFmD6eKXQo79wwBiipX1FykNoAPNJgOM
eE0E1gigDFbprKPQArcwF6FU5tAT1GLP9APkGheaxYpkWL1IllkZItkiiRZ99mSNTp2k43U81iTQ
RUJ2eRl+RIVIVUis9SSbkwKEVEpaZJJU5WQWYUkfQw/MBOSdupGX0UZvGhQcRoc4idSaUh5U1Jvk
7TgnGjGGdQ0CjQV5WS2QtiMPAj5WRNhd8cyDlqOJRWlRM9pwgykrVxJjzC6ldPKLArC0kk8rr+RY
S4WuyjqpL5zg6uur2aTyCqqp2rXdsdwp+iWyzP7R3Xx7NCutHwiGXSeCatNmS9cdKugBxre7fSvu
uFcMwsIT6KKGnH/otuuuES4EIW+elchr77050ECDdM/q6++/M/AbIcAEF5yCwNYarLDC2P5i7sIQ
K+ztunhEbHHBUlV78cb/YsIgxyDr663GIZcMgw3wmqxyvPmu7HIeCb8sc1Qxz2zzzTjnrPPOPPcs
QwgAOw==
"""

STOCK_DATA = {
    "img_not_supported": {
        "type": "data",
        "data": _img_notsupported,
        "format": "gif",
    }
}


class StockImage(object):
    """Maintain references to image name and file.
    When image is used, the class maintains it on memory for tkinter"""

    _stock = STOCK_DATA
    _cached = {}
    _formats = TK_IMAGE_FORMATS

    @classmethod
    def clear_cache(cls):
        """Call this before closing tk root"""
        # Prevent tkinter errors on python 2 ??
        for key in cls._cached:
            cls._cached[key] = None
        cls._cached = {}

    @classmethod
    def register(cls, key, filename):
        """Register a image file using key"""

        if key in cls._stock:
            logger.info("Warning, replacing resource %s", key)
        cls._stock[key] = {"type": "custom", "filename": filename}
        logger.info("%s registered as %s", filename, key)

    @classmethod
    def register_from_data(cls, key, format, data):
        """Register a image data using key"""

        if key in cls._stock:
            logger.info("Warning, replacing resource %s", key)
        cls._stock[key] = {"type": "data", "data": data, "format": format}
        logger.info("%s registered as %s", "data", key)

    @classmethod
    def register_created(cls, key, image):
        """Register an already created image using key"""

        if key in cls._stock:
            logger.info("Warning, replacing resource {0}", key)
        cls._stock[key] = {"type": "created", "image": image}
        logger.info("%s registered as %s", "data", key)

    @classmethod
    def is_registered(cls, key):
        return key in cls._stock

    @classmethod
    def register_from_dir(cls, dir_path, prefix="", ext=TK_IMAGE_FORMATS):
        """List files from dir_path and register images with
            filename as key (without extension)

        :param str dir_path: path to search for images.
        :param str prefix: Additionaly a prefix for the key can be provided,
            so the resulting key will be prefix + filename
        :param iterable ext: list of file extensions to load. Defaults to
            tk supported image extensions. Example ('.jpg', '.png')
        """

        for filename in os.listdir(dir_path):
            name, file_ext = os.path.splitext(filename)
            if file_ext in ext:
                fkey = "{0}{1}".format(prefix, name)
                cls.register(fkey, os.path.join(dir_path, filename))

    @classmethod
    def _load_image(cls, rkey):
        """Load image from file or return the cached instance."""

        v = cls._stock[rkey]
        img = None
        itype = v["type"]
        from_ = itype
        if itype in ("stock", "data"):
            img = tk.PhotoImage(format=v["format"], data=v["data"])
        elif itype == "created":
            img = v["image"]
        else:
            # custom
            fpath = v["filename"]
            from_ = fpath
            fname = os.path.basename(fpath)
            name, file_ext = os.path.splitext(fname)
            file_ext = str(file_ext).lower()

            if file_ext in TK_PHOTO_FORMATS:
                img = tk.PhotoImage(file=fpath)
            elif file_ext in TK_BITMAP_FORMATS:
                img = tk.BitmapImage(file=fpath)
            else:
                try:
                    from PIL import Image, ImageTk

                    aux = Image.open(fpath)
                    img = ImageTk.PhotoImage(aux)
                except ModuleNotFoundError:
                    msg = (
                        "Error loading image %s, try installing Pillow module."
                    )
                    logger.error(msg, fpath)
                    img = cls.get("img_not_supported")

        cls._cached[rkey] = img
        logger.info("Loaded resource %s from %s.", rkey, from_)
        return img

    @classmethod
    def get(cls, rkey):
        """Get image previously registered with key rkey.
        If key not exist, raise StockImageException
        """

        if rkey in cls._cached:
            logger.info("Resource %s is in cache.", rkey)
            return cls._cached[rkey]
        if rkey in cls._stock:
            img = cls._load_image(rkey)
            return img
        else:
            raise StockImageException("StockImage: %s not registered." % rkey)

    @classmethod
    def as_iconbitmap(cls, rkey):
        """Get image path for use in iconbitmap property"""
        img = None
        if rkey in cls._stock:
            data = cls._stock[rkey]
            if data["type"] not in ("stock", "data", "image"):
                fpath = data["filename"]
                fname = os.path.basename(fpath)
                name, file_ext = os.path.splitext(fname)
                file_ext = str(file_ext).lower()

                if file_ext in TK_BITMAP_FORMATS:
                    img = BITMAP_TEMPLATE.format(fpath)
        return img
