r"""Deprecation support for functions that have been replaced by equivalents

  _____   ______  _____   _____   ______  _____         _______  ______  _____
 |  __ \ |  ____||  __ \ |  __ \ |  ____|/ ____|    /\ |__   __||  ____||  __ \
 | |  | || |__   | |__) || |__) || |__  | |        /  \   | |   | |__   | |  | |
 | |  | ||  __|  |  ___/ |  _  / |  __| | |       / /\ \  | |   |  __|  | |  | |
 | |__| || |____ | |     | | \ \ | |____| |____  / ____ \ | |   | |____ | |__| |
 |_____/ |______||_|     |_|  \_\|______|\_____|/_/    \_\|_|   |______||_____/

"""
import re

import omni.graph.core as og
import omni.graph.tools as ogt

from ..lookup_tables import OGN_NAMES_TO_TYPES, USD_NAMES_TO_TYPES

# Pattern match for OGN style type names
# MATCH: BaseType, [TupleCount]|None, []|None - e.g. int[3][] = "int",[3],[]
RE_OGN_ATTRIBUTE_TYPE_PATTERN = re.compile(r"(^[^\[]+)(\[[0-9]+\]){0,1}(\[\]){0,1}")

# Pattern matches for USD style type names. The rules for USD names are a little more complex so they require
# multiple patterns to fully grok. (e.g. an int[4] is "int4" but a colord[4] is "color4d")
# MATCH: BaseType64, TupleCount|None, []|None  - e.g. int64 = "int64",None,None
RE_USD_ATTRIBUTE_64_TYPE_PATTERN = re.compile(r"^([a-zA-Z]+64)([0-9]+){0,1}(\[\]){0,1}")
# MATCH: BaseType, TupleCount|None, h|d|f|None, []|None - e.g. quat3d[] = "quat",3,d,[]
RE_USD_ATTRIBUTE_TYPE_PATTERN = re.compile(r"^([a-zA-Z]+)([0-9]+){0,1}([hdf]){0,1}(\[\]){0,1}")

# Mapping of the .ogn base data types to the corresponding og.BaseDataType values
BASE_DATA_TYPE_MAP = {
    "bool": og.BaseDataType.BOOL,
    "bundle": og.BaseDataType.RELATIONSHIP,
    "double": og.BaseDataType.DOUBLE,
    "execution": og.BaseDataType.UINT,
    "float": og.BaseDataType.FLOAT,
    "half": og.BaseDataType.HALF,
    "int": og.BaseDataType.INT,
    "int64": og.BaseDataType.INT64,
    "objectId": og.BaseDataType.UINT64,
    "path": og.BaseDataType.UCHAR,
    "string": og.BaseDataType.UCHAR,
    "token": og.BaseDataType.TOKEN,
    "uchar": og.BaseDataType.UCHAR,
    "uint": og.BaseDataType.UINT,
    "uint64": og.BaseDataType.UINT64,
}

# Mapping of the .ogn role names to the corresponding og.AttributeRole values
ROLE_MAP = {
    "color": og.AttributeRole.COLOR,
    "execution": og.AttributeRole.EXECUTION,
    "frame": og.AttributeRole.FRAME,
    "matrix": og.AttributeRole.MATRIX,
    "none": og.AttributeRole.NONE,
    "normal": og.AttributeRole.NORMAL,
    "objectId": og.AttributeRole.OBJECT_ID,
    "path": og.AttributeRole.PATH,
    "point": og.AttributeRole.POSITION,
    "quat": og.AttributeRole.QUATERNION,
    "string": og.AttributeRole.TEXT,
    "texcoord": og.AttributeRole.TEXCOORD,
    "timecode": og.AttributeRole.TIMECODE,
    "transform": og.AttributeRole.TRANSFORM,
    "vector": og.AttributeRole.VECTOR,
}


# ==============================================================================================================
@ogt.deprecated_function("Use og.AttributeType.type_from_ogn_type_name instead")
def attribute_type_from_ogn_type_name(ogn_type_name: str) -> og.Type:
    """Construct an attribute type object from an OGN style type name"""
    type_match = RE_OGN_ATTRIBUTE_TYPE_PATTERN.match(ogn_type_name)
    if not type_match:
        raise AttributeError(f"Attribute type '{ogn_type_name}' does not match known OGN type names")

    try:
        (base_type, role) = OGN_NAMES_TO_TYPES[type_match.group(1)]
    except KeyError as error:
        raise AttributeError(f"Base type '{type_match.group(1)}' is not a supported OGN type") from error

    tuple_count = 1 if type_match.group(2) is None else int(type_match.group(2)[1])
    array_depth = 0 if type_match.group(3) is None and role in [og.AttributeRole.TEXT, og.AttributeRole.PATH] else 1
    is_matrix_type = role in [og.AttributeRole.MATRIX, og.AttributeRole.TRANSFORM, og.AttributeRole.FRAME]
    if is_matrix_type:
        tuple_count *= tuple_count
    return og.Type(base_type, tuple_count, array_depth, role)


# ==============================================================================================================
@ogt.deprecated_function("Use og.AttributeType.type_from_sdf_type_name instead")
def attribute_type_from_usd_type_name(usd_type_name: str) -> og.Type:
    """Construct an attribute type object from a USD style type name"""
    # The 64 type pattern (int64, uint64) has to be applied first so that the base type includes it
    type_match = RE_USD_ATTRIBUTE_64_TYPE_PATTERN.match(usd_type_name)
    if type_match:
        (full_type, tuple_count, array_pattern) = type_match.groups()
        flavour = None
    else:
        type_match = RE_USD_ATTRIBUTE_TYPE_PATTERN.match(usd_type_name)
        if not type_match:
            raise AttributeError(f"Attribute type '{usd_type_name}' does not match known USD type names")
        (full_type, tuple_count, flavour, array_pattern) = type_match.groups()
        # Reassemble the role names (quat3d extracts as "quat",3,"d",None - need "quatd" to grok the types)
        full_type = f"{full_type}{flavour}" if flavour is not None else full_type

    tuple_count = 1 if tuple_count is None else int(tuple_count)
    array_depth = 0 if array_pattern is None else 1
    try:
        (base_type, role, override_tuple_count) = USD_NAMES_TO_TYPES[full_type]
        if override_tuple_count is not None:
            tuple_count = override_tuple_count
    except KeyError as error:
        raise AttributeError(f"Base type '{full_type}' is not a supported USD type") from error

    is_matrix_type = usd_type_name.startswith("matrix")
    if is_matrix_type:
        tuple_count *= tuple_count
    return og.Type(base_type, tuple_count, array_depth, role)
