# Python Imports
import os, subprocess, hashlib, threading
from os.path import isdir, isfile, join


# Gtk imports
import gi
gi.require_version('Gdk', '3.0')

from gi.repository import GdkPixbuf
from xdg.DesktopEntry import DesktopEntry


# Application imports




def threaded(fn):
    def wrapper(*args, **kwargs):
        threading.Thread(target=fn, args=args, kwargs=kwargs).start()
    return wrapper

class Icon:
    def __init__(self, settings):
        self.settings          = settings
        self.thubnailGen       = settings.getThumbnailGenerator()
        self.vidsList          = settings.returnVidsFilter()
        self.imagesList        = settings.returnImagesFilter()
        self.GTK_ORIENTATION   = settings.returnIconImagePos()
        self.usrHome           = settings.returnUserHome()
        self.iconContainerWH   = settings.returnContainerWH()
        self.systemIconImageWH = settings.returnSystemIconImageWH()
        self.viIconWH          = settings.returnVIIconWH()
        self.SCRIPT_PTH        = os.path.dirname(os.path.realpath(__file__)) + "/"
        self.INTERNAL_ICON_PTH = self.SCRIPT_PTH + "../resources/icons/text.png"


    def createIcon(self, dir, file):
        fullPath = dir + "/" + file
        return self.getIconImage(file, fullPath)

    def createThumbnail(self, dir, file):
        fullPath = dir + "/" + file
        try:
            # Video thumbnail
            if file.lower().endswith(self.vidsList):
                fileHash   = hashlib.sha256(str.encode(fullPath)).hexdigest()
                hashImgPth = self.usrHome + "/.thumbnails/normal/" + fileHash + ".png"

                if isfile(hashImgPth) == False:
                    self.generateVideoThumbnail(fullPath, hashImgPth)

                thumbnl = self.createScaledImage(hashImgPth, self.viIconWH)
                if thumbnl == None: # If no icon whatsoever, return internal default
                    thumbnl = GdkPixbuf.Pixbuf.new_from_file(self.SCRIPT_PTH + "../resources/icons/video.png")

            return thumbnl
        except Exception as e:
            print("Thumbnail generation issue:")
            print( repr(e) )
            return GdkPixbuf.Pixbuf.new_from_file(self.SCRIPT_PTH + "../resources/icons/video.png")


    def getIconImage(self, file, fullPath):
        try:
            thumbnl = None

            # Video icon
            if file.lower().endswith(self.vidsList):
                thumbnl = GdkPixbuf.Pixbuf.new_from_file(self.SCRIPT_PTH + "../resources/icons/video.png")
            # Image Icon
            elif file.lower().endswith(self.imagesList):
                thumbnl = self.createScaledImage(fullPath, self.viIconWH)
            # .desktop file parsing
            elif fullPath.lower().endswith( ('.desktop',) ):
                thumbnl = self.parseDesktopFiles(fullPath)

            return thumbnl
        except Exception as e:
            print("Icon generation issue:")
            print( repr(e) )
            return GdkPixbuf.Pixbuf.new_from_file(self.INTERNAL_ICON_PTH)

    def parseDesktopFiles(self, fullPath):
        try:
            xdgObj      = DesktopEntry(fullPath)
            icon        = xdgObj.getIcon()
            altIconPath = ""

            if "steam" in icon:
                steamIconsDir = self.usrHome + "/.thumbnails/steam_icons/"
                name          = xdgObj.getName()
                fileHash      = hashlib.sha256(str.encode(name)).hexdigest()

                if isdir(steamIconsDir) == False:
                    os.mkdir(steamIconsDir)

                hashImgPth = steamIconsDir + fileHash + ".jpg"
                if isfile(hashImgPth) == True:
                    # Use video sizes since headers are bigger
                    return self.createScaledImage(hashImgPth, self.viIconWH)

                execStr   = xdgObj.getExec()
                parts     = execStr.split("steam://rungameid/")
                id        = parts[len(parts) - 1]
                imageLink = "https://steamcdn-a.akamaihd.net/steam/apps/" + id + "/header.jpg"
                proc      = subprocess.Popen(["wget", "-O", hashImgPth, imageLink])
                proc.wait()

                # Use video thumbnail sizes since headers are bigger
                return self.createScaledImage(hashImgPth, self.viIconWH)
            elif os.path.exists(icon):
                return self.createScaledImage(icon, self.systemIconImageWH)
            else:
                iconsDirs   = ["/usr/share/pixmaps", "/usr/share/icons", self.usrHome + "/.icons" ,]
                altIconPath = ""

                for iconsDir in iconsDirs:
                    altIconPath = self.traverseIconsFolder(iconsDir, icon)
                    if altIconPath != "":
                        break

                return self.createScaledImage(altIconPath, self.systemIconImageWH)
        except Exception as e:
            print(".desktop icon generation issue:")
            print( repr(e) )
            return None


    def traverseIconsFolder(self, path, icon):
        altIconPath = ""

        for (dirpath, dirnames, filenames) in os.walk(path):
            for file in filenames:
                appNM = "application-x-" + icon
                if icon in file or appNM in file:
                    altIconPath = dirpath + "/" + file
                    break

        return altIconPath


    def createScaledImage(self, path, wxh):
        try:
            pixbuf       = GdkPixbuf.Pixbuf.new_from_file(path)
            scaledPixBuf = pixbuf.scale_simple(wxh[0], wxh[1], 2)  # 2 = BILINEAR and is best by default
            return scaledPixBuf
        except Exception as e:
            print("Image Scaling Issue:")
            print( repr(e) )
            return None

    def createFromFile(self, path):
        try:
            return GdkPixbuf.Pixbuf.new_from_file(path)
        except Exception as e:
            print("Image from file Issue:")
            print( repr(e) )
            return None

    def returnGenericIcon(self):
        return GdkPixbuf.Pixbuf.new_from_file(self.INTERNAL_ICON_PTH)


    def generateVideoThumbnail(self, fullPath, hashImgPth):
        proc = None
        try:
            # Stream duration
            command  = ["ffprobe", "-v", "error", "-select_streams", "v:0", "-show_entries", "stream=duration", "-of", "default=noprint_wrappers=1:nokey=1", fullPath]
            data     = subprocess.run(command, stdout=subprocess.PIPE)
            duration = data.stdout.decode('utf-8')

            # Format (container) duration
            if "N/A" in duration:
                command  = ["ffprobe", "-v", "error", "-show_entries", "format=duration", "-of", "default=noprint_wrappers=1:nokey=1", fullPath]
                data     = subprocess.run(command , stdout=subprocess.PIPE)
                duration = data.stdout.decode('utf-8')

            # Stream duration type: image2
            if "N/A" in duration:
                command  = ["ffprobe", "-v", "error", "-select_streams", "v:0", "-f", "image2", "-show_entries", "stream=duration", "-of", "default=noprint_wrappers=1:nokey=1", fullPath]
                data     = subprocess.run(command, stdout=subprocess.PIPE)
                duration = data.stdout.decode('utf-8')

            # Format (container) duration type: image2
            if "N/A" in duration:
                command  = ["ffprobe", "-v", "error", "-f", "image2", "-show_entries", "format=duration", "-of", "default=noprint_wrappers=1:nokey=1", fullPath]
                data     = subprocess.run(command , stdout=subprocess.PIPE)
                duration = data.stdout.decode('utf-8')

            # Get frame roughly 35% through video
            grabTime = str( int( float( duration.split(".")[0] ) * 0.35) )
            command  = ["ffmpeg", "-ss", grabTime, "-an", "-i", fullPath, "-s", "320x180", "-vframes", "1", hashImgPth]
            proc     = subprocess.Popen(command, stdout=subprocess.PIPE)
            proc.wait()
        except Exception as e:
            print("Video thumbnail generation issue in thread:")
            print( repr(e) )
