#
# This file is part of Reclaimer.
#
# For authors and copyright check AUTHORS.TXT
#
# Reclaimer is free software under the GNU General Public License v3.0.
# See LICENSE for more information.
#

from copy import copy, deepcopy

try:
    from mozzarilla.widgets.field_widgets import ReflexiveFrame,\
         HaloRawdataFrame, TextFrame, ColorPickerFrame, EntryFrame,\
         SoundSampleFrame, DynamicArrayFrame, Halo3BitmapTagFrame
except Exception:
    ReflexiveFrame = HaloRawdataFrame = TextFrame = ColorPickerFrame =\
                     EntryFrame = SoundSampleFrame = DynamicArrayFrame = \
                     Halo3BitmapTagFrame = None
from reclaimer.common_descs import *
from reclaimer.h3.field_types import H3TagRef, H3Reflexive, H3RawdataRef
from reclaimer.h3.constants import DYN_NAME_PATH, STEPTREE, NAME_MAP, WIDGET,\
     TOOLTIP, COMMENT, MAX, DEFAULT, VISIBLE, SIZE, MAX_REFLEXIVE_COUNT,\
     h3_tag_class_fcc_to_ext
from reclaimer.h3.enums import *

from supyr_struct.defs.block_def import BlockDef


def h3_tag_class(*args, **kwargs):
    '''
    A macro for creating a tag_class enum desc with the
    enumerations set to the provided tag_class fcc's.
    '''
    classes = []
    for four_cc in args:
        classes.append((h3_tag_class_fcc_to_ext[four_cc], four_cc))

    return UEnum32(
        'tag_class',
        *(tuple(sorted(classes)) + (("NONE", 0xffffffff),) ),
        DEFAULT=0xffffffff, GUI_NAME='', WIDGET_WIDTH=20, **kwargs
        )

def h3_reflexive(name, substruct, max_count=MAX_REFLEXIVE_COUNT, *names, **desc):
    '''This function serves to macro the creation of a reflexive'''
    desc.update(
        INCLUDE=h3_reflexive_struct,
        STEPTREE=Array(name + " array",
            SIZE=".size", MAX=max_count,
            SUB_STRUCT=substruct, WIDGET=ReflexiveFrame
            ),
        SIZE=12
        )
    if DYN_NAME_PATH in desc:
        desc[STEPTREE][DYN_NAME_PATH] = desc.pop(DYN_NAME_PATH)
    if names:
        name_map = {}
        for i in range(len(names)):
            e_name = BlockDef.str_to_name(None, names[i])
            name_map[e_name] = i

        desc[STEPTREE][NAME_MAP] = name_map

    return H3Reflexive(name, **desc)


def h3_rawdata_ref(name, f_type=BytearrayRaw, max_size=None,
                   widget=HaloRawdataFrame, **kwargs):
    '''This function serves to macro the creation of a rawdata reference'''
    ref_struct = dict(h3_rawdata_ref_struct)
    if COMMENT in kwargs: ref_struct[COMMENT] = kwargs.pop(COMMENT)
    if TOOLTIP in kwargs: ref_struct[TOOLTIP] = kwargs.pop(TOOLTIP)
    if max_size is not None:
        ref_struct[0] = dict(ref_struct[0])
        ref_struct[0][MAX] = max_size
        kwargs[MAX] = max_size

    if widget is not None:
        kwargs[WIDGET] = widget

    return H3RawdataRef(name,
        INCLUDE=ref_struct,
        STEPTREE=f_type("data", GUI_NAME="", SIZE=".size", **kwargs))


def h3_dependency(name='tag ref', valid_ids=None, **kwargs):
    '''This function serves to macro the creation of a tag dependency'''
    if isinstance(valid_ids, tuple):
        valid_ids = h3_tag_class(*valid_ids)
    elif isinstance(valid_ids, str):
        valid_ids = h3_tag_class(valid_ids)
    elif valid_ids is None:
        valid_ids = valid_h3_tags

    return H3TagRef(name,
        valid_ids,
        INCLUDE=tag_ref_struct,
        STEPTREE=StrTagRef(
            "filepath", SIZE=tag_ref_str_size, GUI_NAME="", MAX=254),
        **kwargs
        )

def h3_blam_header(tagid, version=1):
    '''This function serves to macro the creation of a tag header'''
    header_desc = dict(h3_tag_header)
    header_desc[1] = dict(header_desc[1])
    header_desc[5] = dict(header_desc[5])
    header_desc[1][DEFAULT] = tagid
    header_desc[5][DEFAULT] = version
    return header_desc


valid_h3_tags = h3_tag_class(*h3_tag_class_fcc_to_ext.keys())


# ###########################################################################
# The order of element in all the enumerators is important(DONT SHUFFLE THEM)
# ###########################################################################

#Shared Enumerator options
old_materials_list = materials_list
# old materials list that is referenced in tags, but seems to be unused
del materials_list


# Descriptors
h3_blam_engine_id = dict(blam_engine_id)
h3_blam_engine_id[DEFAULT] = "b3am"
h3_tag_header = Struct("blam_header",
    Pad(36),
    UEnum32("tag class",
        GUI_NAME="tag class", INCLUDE=valid_h3_tags, EDITABLE=False
        ),
    UInt32("checksum", DEFAULT=0x4D6F7A7A, EDITABLE=False),
    UInt32("header size", DEFAULT=64, EDITABLE=False),
    Bool64("flags",
        "edited with mozz",
        EDITABLE=False
        ),
    UInt16("version", DEFAULT=1, EDITABLE=False),
    UInt8("integrity0", DEFAULT=0, EDITABLE=False),
    UInt8("integrity1", DEFAULT=255, EDITABLE=False),
    h3_blam_engine_id,
    VISIBLE=VISIBILITY_METADATA, SIZE=64
    )

# these structs replace the above ones when used outside a map
h3_tag_index_ref_struct = H3TagRef('dependency',
    valid_h3_tags,
    SInt32("path pointer", VISIBLE=VISIBILITY_METADATA, EDITABLE=False),
    SInt32("path length", MAX=254, VISIBLE=VISIBILITY_METADATA, EDITABLE=False),
    UInt32("id", VISIBLE=VISIBILITY_METADATA, EDITABLE=False),
    ORIENT='h'
    )

h3_reflexive_struct = H3Reflexive('reflexive',
    SInt32("size", VISIBLE=VISIBILITY_METADATA, EDITABLE=False),
    UInt32("pointer", VISIBLE=VISIBILITY_METADATA, EDITABLE=False, DEFAULT=0xFFFFFFFF),
    UInt32("id", VISIBLE=VISIBILITY_METADATA, EDITABLE=False),
    )

h3_rawdata_ref_struct = H3RawdataRef('rawdata ref',
    SInt32("size", GUI_NAME="", SIDETIP="bytes", EDITABLE=False),
    Bool32("flags", VISIBLE=VISIBILITY_METADATA, EDITABLE=False),
    UInt32("raw pointer", VISIBLE=VISIBILITY_METADATA, EDITABLE=False),
    UInt32("pointer", VISIBLE=VISIBILITY_METADATA, EDITABLE=False, DEFAULT=0xFFFFFFFF),
    UInt32("id", VISIBLE=VISIBILITY_METADATA, EDITABLE=False),
    ORIENT='h'
    )

h3_page_offset_info_struct = BitStruct("page_offset_info",
    UBitInt("offset", SIZE=29),
    Bit("fixup"),
    Bit("raw_page"),
    )


def h3_string_id(name, **kwargs):
    return string_id(name, 16, 8, 8, **kwargs)


def h3_page_offset_info(name):
    return BitStruct(name, INCLUDE=h3_page_offset_info_struct)
