"""
Print out which fields of FAST5 files are static or variable for the same experiment.
In a nice hierarchical format.
Given h5dump output of any number of FAST5 files.
Show the constant values with -c flag.

Usage: python3 $0 [h5dump_FAST5_output...] [-c]
"""

from sys import argv
import re

# Class for a hdf5 group
class Group:
    def __init__(self, name, prev_group=None):
        self.name = name
        self.prev_group = prev_group
        self.attrs = []

    def add_attr(self, attr):
        self.attrs.append(attr)

    def print_hier(self, prefix=''):
        for attr in self.attrs:
            if isinstance(attr, Group):
                print(f"{prefix}{attr.name}:")
                attr.print_hier(prefix + '    ')
            else:
                print(f"{prefix}{attr}")

    def print_hier_if_in(self, arr, show_val=False, prefix=''):
        is_dict = type(arr) is dict

        for attr in self.attrs:
            if isinstance(attr, Group):
                print(f"{prefix}{attr.name}:")
                attr.print_hier_if_in(arr, show_val, prefix + '    ')
            else:
                if attr in arr:
                    if show_val and is_dict:
                        print(f"{prefix}{attr}: {arr[attr]}")
                    else:
                        print(f"{prefix}{attr}")

    def __str__(self):
        return str(self.attrs)
    def __repr__(self):
        return str(self.attrs)

args = argv[1:]
if "-c" in args:
    args.remove("-c")
    show_const = True
else:
    show_const = False

attrs = {}
root_group = Group("/")

var = []
const = {}

bracket_pos = 0
group_pos = []

struct_made = False
curr_group = root_group
first_read = True

for fname in args:
    f = open(fname)

    for line in f:
        line = line.split()

        # Add group to structure
        if not struct_made and line[0] == "GROUP" and line[1] != '"/"':

            # Don't repeat the structure for the 'multi' type
            if re.match('"read_.+"', line[1]):
                if first_read:
                    first_read = False
                else:
                    struct_made = True

            if not struct_made:
                group_pos.append(bracket_pos)

                new_group = Group(line[1][1:-1])
                curr_group.add_attr(new_group)

                new_group.prev_group = curr_group
                curr_group = new_group

        if line[0] == "ATTRIBUTE" or line[0] == "DATASET":
            curr_attr = line[1][1:-1]

            # Create empty set for attribute if not already there
            if curr_attr not in attrs:
                attrs[curr_attr] = set()

            # Add attribute to structure
            if not struct_made:
                curr_group.add_attr(curr_attr)

        # Data follows a (0)
        elif line[0] == "(0):":
            # Store attribute's data
            data = " ".join(line[1:])
            attrs[curr_attr].add(data)

        # Closing marker
        if not struct_made and "{" in line:
            bracket_pos += 1

        if not struct_made and "}" in line:
            bracket_pos -= 1

            # Check if group is finished
            if len(group_pos) != 0 and bracket_pos == group_pos[-1]:
                group_pos = group_pos[:-1]
                curr_group = curr_group.prev_group

    if not struct_made:
        struct_made = True

# Decide what's constant and variable
for prop in attrs:
    if len(attrs[prop]) == 1:
        const[prop] = list(attrs[prop])[0]
    else:
        var.append(prop)

# Print properties which are constant and variable
print("CONSTANT")
root_group.print_hier_if_in(const, show_const)
print("\nVARIABLE")
root_group.print_hier_if_in(var, show_const)
