# Copyright (c) 2018-2020, NVIDIA CORPORATION.  All rights reserved.
#
# NVIDIA CORPORATION and its licensors retain all intellectual property
# and proprietary rights in and to this software, related documentation
# and any modifications thereto.  Any use, reproduction, disclosure or
# distribution of this software and related documentation without an express
# license agreement from NVIDIA CORPORATION is strictly prohibited.
#
import carb.settings

from typing import Dict
from collections import namedtuple
from .style import ICON_PATH, THUMBNAIL_PATH

AssetTypeDef = namedtuple("AssetTypeDef", "glyph thumbnail matching_exts")

# The known list of asset types, stored in this singleton variable
_known_asset_types: Dict = None


# Default Asset types
ASSET_TYPE_ANIM_USD = "anim_usd"
ASSET_TYPE_CACHE_USD = "cache_usd"
ASSET_TYPE_CURVE_ANIM_USD = "curve_anim_usd"
ASSET_TYPE_GEO_USD = "geo_usd"
ASSET_TYPE_MATERIAL_USD = "material_usd"
ASSET_TYPE_PROJECT_USD = "project_usd"
ASSET_TYPE_SEQ_USD = "seq_usd"
ASSET_TYPE_SKEL_USD = "skel_usd"
ASSET_TYPE_SKEL_ANIM_USD  = "skel_anim_usd"
ASSET_TYPE_USD_SETTINGS = "settings_usd"
ASSET_TYPE_USD = "usd"
ASSET_TYPE_FBX = "fbx"
ASSET_TYPE_OBJ = "obj"
ASSET_TYPE_MATERIAL = "material"
ASSET_TYPE_IMAGE = "image"
ASSET_TYPE_SOUND = "sound"
ASSET_TYPE_SCRIPT = "script"
ASSET_TYPE_VOLUME = "volume"
ASSET_TYPE_FOLDER = "folder"
ASSET_TYPE_ICON = "icon"
ASSET_TYPE_HIDDEN = "hidden"
ASSET_TYPE_UNKNOWN = "unknown"

def _init_asset_types():
    global _known_asset_types
    _known_asset_types = {}

    _known_asset_types[ASSET_TYPE_USD_SETTINGS] = AssetTypeDef(
        f"{ICON_PATH}/settings_usd.svg",
        f"{THUMBNAIL_PATH}/settings_usd_256.png",
        [".settings.usd", ".settings.usda", ".settings.usdc", ".settings.usdz"],
    )
    _known_asset_types[ASSET_TYPE_ANIM_USD] = AssetTypeDef(
        f"{ICON_PATH}/anim_usd.svg",
        f"{THUMBNAIL_PATH}/anim_usd_256.png",
        [".anim.usd", ".anim.usda", ".anim.usdc", ".anim.usdz"],
    )
    _known_asset_types[ASSET_TYPE_CACHE_USD] = AssetTypeDef(
        f"{ICON_PATH}/cache_usd.svg",
        f"{THUMBNAIL_PATH}/cache_usd_256.png",
        [".cache.usd", ".cache.usda", ".cache.usdc", ".cache.usdz"],
    )
    _known_asset_types[ASSET_TYPE_CURVE_ANIM_USD] = AssetTypeDef(
        f"{ICON_PATH}/anim_usd.svg",
        f"{THUMBNAIL_PATH}/curve_anim_usd_256.png",
        [".curveanim.usd", ".curveanim.usda", ".curveanim.usdc", ".curveanim.usdz"],
    )
    _known_asset_types[ASSET_TYPE_GEO_USD] = AssetTypeDef(
        f"{ICON_PATH}/geo_usd.svg",
        f"{THUMBNAIL_PATH}/geo_usd_256.png",
        [".geo.usd", ".geo.usda", ".geo.usdc", ".geo.usdz"],
    )
    _known_asset_types[ASSET_TYPE_MATERIAL_USD] = AssetTypeDef(
        f"{ICON_PATH}/material_usd.png",
        f"{THUMBNAIL_PATH}/material_usd_256.png",
        [".material.usd", ".material.usda", ".material.usdc", ".material.usdz"],
    )
    _known_asset_types[ASSET_TYPE_PROJECT_USD] = AssetTypeDef(
        f"{ICON_PATH}/project_usd.svg",
        f"{THUMBNAIL_PATH}/project_usd_256.png",
        [".project.usd", ".project.usda", ".project.usdc", ".project.usdz"],
    )
    _known_asset_types[ASSET_TYPE_SEQ_USD] = AssetTypeDef(
        f"{ICON_PATH}/sequence_usd.svg",
        f"{THUMBNAIL_PATH}/sequence_usd_256.png",
        [".seq.usd", ".seq.usda", ".seq.usdc", ".seq.usdz"],
    )
    _known_asset_types[ASSET_TYPE_SKEL_USD] = AssetTypeDef(
        f"{ICON_PATH}/skel_usd.svg",
        f"{THUMBNAIL_PATH}/skel_usd_256.png",
        [".skel.usd", ".skel.usda", ".skel.usdc", ".skel.usdz"],
    )
    _known_asset_types[ASSET_TYPE_SKEL_ANIM_USD] = AssetTypeDef(
        f"{ICON_PATH}/anim_usd.svg",
        f"{THUMBNAIL_PATH}/skel_anim_usd_256.png",
        [".skelanim.usd", ".skelanim.usda", ".skelanim.usdc", ".skelanim.usdz"],
    )
    _known_asset_types[ASSET_TYPE_FBX] = AssetTypeDef(
        f"{ICON_PATH}/usd_stage.svg", f"{THUMBNAIL_PATH}/fbx_256.png", [".fbx"]
    )
    _known_asset_types[ASSET_TYPE_OBJ] = AssetTypeDef(
        f"{ICON_PATH}/usd_stage.svg", f"{THUMBNAIL_PATH}/obj_256.png", [".obj"]
    )
    _known_asset_types[ASSET_TYPE_MATERIAL] = AssetTypeDef(
        f"{ICON_PATH}/mdl.svg", f"{THUMBNAIL_PATH}/mdl_256.png", [".mdl", ".mtlx"]
    )
    _known_asset_types[ASSET_TYPE_IMAGE] = AssetTypeDef(
        f"{ICON_PATH}/image.svg",
        f"{THUMBNAIL_PATH}/image_256.png",
        [".bmp", ".gif", ".jpg", ".jpeg", ".png", ".tga", ".tif", ".tiff", ".hdr", ".dds", ".exr", ".psd", ".ies", ".tx"],
    )
    _known_asset_types[ASSET_TYPE_SOUND] = AssetTypeDef(
        f"{ICON_PATH}/sound.svg",
        f"{THUMBNAIL_PATH}/sound_256.png",
        [".wav", ".wave", ".ogg", ".oga", ".flac", ".fla", ".mp3", ".m4a", ".spx", ".opus", ".adpcm"],
    )
    _known_asset_types[ASSET_TYPE_SCRIPT] = AssetTypeDef(
        f"{ICON_PATH}/script.svg", f"{THUMBNAIL_PATH}/script_256.png", [".py"]
    )
    _known_asset_types[ASSET_TYPE_VOLUME] = AssetTypeDef(
        f"{ICON_PATH}/volume.svg",
        f"{THUMBNAIL_PATH}/volume_256.png",
        [".nvdb", ".vdb"],
    )
    _known_asset_types[ASSET_TYPE_ICON] = AssetTypeDef(None, None, [".svg"])
    _known_asset_types[ASSET_TYPE_HIDDEN] = AssetTypeDef(None, None, [".thumbs"])

    try:
        # avoid dependency on USD in this extension and only use it when available
        import omni.usd
    except ImportError:
        pass
    else:
        # readable_usd_dotted_file_exts() is auto-generated by querying USD;
        # however, it includes some items that we've assigned more specific
        # roles (ie, .mdl).  So do this last, and subtract out any already-
        # known types.

        known_exts = set()
        for asset_type_def in _known_asset_types.values():
            known_exts.update(asset_type_def.matching_exts)
        usd_exts = [
            x for x in omni.usd.readable_usd_dotted_file_exts()
            if x not in known_exts
        ]
        _known_asset_types[ASSET_TYPE_USD] = AssetTypeDef(
            f"{ICON_PATH}/usd_stage.svg",
            f"{THUMBNAIL_PATH}/usd_stage_256.png",
            usd_exts,
        )

if _known_asset_types is None:
    _init_asset_types()


def register_file_extensions(asset_type: str, exts: [str], replace: bool = False):
    """
    Adds an asset type to the recognized list.

    Args:
        asset_type (str): Name of asset type.
        exts ([str]): List of extensions to associate with this asset type, e.g. [".usd", ".usda"].
        replace (bool): If True, replaces extensions in the existing definition. Otherwise, append
            to the existing list.

    """
    if not asset_type or exts == None:
        return
    global _known_asset_types
    if asset_type in _known_asset_types:
        glyph = _known_asset_types[asset_type].glyph
        thumbnail = _known_asset_types[asset_type].thumbnail
        if replace:
            _known_asset_types[asset_type] = AssetTypeDef(glyph, thumbnail, exts)
        else:
            exts.extend(_known_asset_types[asset_type].matching_exts)
            _known_asset_types[asset_type] = AssetTypeDef(glyph, thumbnail, exts)
    else:
        _known_asset_types[asset_type] = AssetTypeDef(None, None, exts)


def is_asset_type(filename: str, asset_type: str) -> bool:
    """
    Returns True if given filename is of specified type.

    Args:
        filename (str)
        asset_type (str): Tested type name.

    Returns:
        bool

    """
    global _known_asset_types
    if not (filename and asset_type):
        return False
    elif asset_type not in _known_asset_types:
        return False
    return any([filename.lower().endswith(ext.lower()) for ext in _known_asset_types[asset_type].matching_exts])


def get_asset_type(filename: str) -> str:
    """
    Returns asset type, based on extension of given filename.

    Args:
        filename (str)

    Returns:
        str

    """
    if not filename:
        return None
    global _known_asset_types
    for asset_type in _known_asset_types:
        if is_asset_type(filename, asset_type):
            return asset_type
    return ASSET_TYPE_UNKNOWN


def get_icon(filename: str) -> str:
    """
    Returns icon for specified file.

    Args:
        filename (str)

    Returns:
        str: Fullpath to the icon file, None if not found.

    """
    if not filename:
        return None
    icon = None
    asset_type = get_asset_type(filename)
    global _known_asset_types
    if asset_type in _known_asset_types:
        icon = _known_asset_types[asset_type].glyph
    return icon


def get_thumbnail(filename: str) -> str:
    """
    Returns thumbnail for specified file.

    Args:
        filename (str)

    Returns:
        str: Fullpath to the thumbnail file, None if not found.

    """
    if not filename:
        return None
    thumbnail = None
    asset_type = get_asset_type(filename)
    global _known_asset_types
    if asset_type == ASSET_TYPE_ICON:
        thumbnail = filename
    else:
        if asset_type in _known_asset_types:
            thumbnail = _known_asset_types[asset_type].thumbnail

    return thumbnail or f"{THUMBNAIL_PATH}/unknown_file_256.png"
