{{
import datetime
import malcat
from helpers import naturalsize

def pval(key, val=None, fmt="{}", va=False, pa=False, rva=False, size=False, kalign=30, valign=0, formated=False):
    r = "[normal]{}[/normal]:".format(key)
    lr = len(r) - 17
    if lr < kalign:
        r += (" "*(kalign-lr))
    if isinstance(val, malcat.StructAccess) or isinstance(val, malcat.FieldAccess):
        if val.has_enum and val.enum:
            d = "[color6]{}[/color6]([dim]{}[/dim])".format(val.enum, fmt.format(val.value))
            formated = True
            ld = len(d) - len("[color3][/color3][dim][/dim]")
        else:
            if size:
                d = naturalsize(val.value, binary=True)
            else:
                toprint = val.value
                if type(toprint) == str:
                    toprint = toprint.replace("[", "\\[")
                d = fmt.format(toprint)
            ld = len(d)
        val = val.value
    elif size and type(val) == int:
        d = naturalsize(val, binary=True)
        ld = len(d)
    else:
        d = fmt.format(val)
        ld = len(d)
    if not formated:
        if type(val) == int: 
            if val == 0:
                grp = "dim"
            elif pa:
                grp = "fa"
            elif rva:
                grp = "rva"
            elif va:
                grp = "va"
            else:
                grp = "normal"
        else:
            grp = "normal"
        d = "[{}]{}[/{}]".format(grp,d,grp)
    if ld < valign:
        d += (" "*(valign-ld))
    write(r+d)  

def bitfieldpp(fa):
    s = []
    for i in range(fa.count - 1, -1, -1):
        bit = fa.at(i)
        if bit.value:
            s.append("[color5]{}[/color5]([dim]{:X}[/dim])".format(bit.name, 1 << i))
    if s:
        return  " + ".join(s)
    else:
        return "[dim]0[/dim]"

def pbitfield(key, fa, kalign=30):    
    r = "[normal]{}[/normal]:".format(key)
    lr = len(r) - 17
    if lr < kalign:
        r += (" "*(kalign-lr))
    write(r + bitfieldpp(fa))

def pkv(d):
    if d["Type"] == 8:
        return d["Value"]["String"].replace("[", "\\[")
    elif d["Type"] == 9:
        return f"Array of {d["Value"]["Size"]} elements of {d["Value"].Type.enum}"
    else:
        return str(d["Value"])
}}

[color1]GGUF Header[/color1]
  {{ pval("File format version", analysis.struct["GGUFHeader"]["Version"]) }} 
  {{ pval("Number of Tensors", analysis.struct["GGUFHeader"]["NumberOfTensors"], valign=28) }} {{ pval("Number of Values",  analysis.struct["GGUFHeader"]["NumberOfValues"]) }}

[color1]Dictionnary[/color1]
{{ for d in analysis.struct["Dictionnary"]: }}
    {{ pval(d["Key"]["String"], pkv(d)) }} 
{{:endfor}}

[color1]Tensors[/color1]
{{ for ti in analysis.struct["TensorInformations"]: }}
  [color2]{{write(ti["Name"]["String"].replace("[", "\\["))}}[/color2]:
    {{ pval("Type", ti.TensorType, valign=26) }} {{ pval("Dimensions", "x".join([str(v.value) for v in ti.NumberOfElements])) }}
    {{ pval("Offset", ti["Offset"] + analysis.parser.start_of_tensors, fmt="{:x}", pa=True) }} 
{{:endfor}}
