"""
Common Helper utilities for transformers
"""


def get_field_on_block(block, field_name, default_value=None):
    """
    Get the field value that is directly set on the xblock.
    Do not get the inherited value since field inheritance
    returns value from only a single parent chain
    (e.g., doesn't take a union in DAGs).
    """
    try:
        if block.fields[field_name].is_set_on(block):
            return getattr(block, field_name)
    except KeyError:
        pass
    return default_value


def collect_merged_boolean_field(
        block_structure,
        transformer,
        xblock_field_name,
        merged_field_name,
):
    """
    Collects a boolean xBlock field of name xblock_field_name
    for the given block_structure and transformer.  The boolean
    value is percolated down the hierarchy of the block_structure
    and stored as a value of merged_field_name in the
    block_structure.

    Assumes that the boolean field is False, by default. So,
    the value is ANDed across all parents for blocks with
    multiple parents and ORed across all ancestors down a single
    hierarchy chain.
    """

    for block_key in block_structure.topological_traversal():
        # compute merged value of the boolean field from all parents
        parents = block_structure.get_parents(block_key)
        all_parents_merged_value = all(  # pylint: disable=invalid-name
            block_structure.get_transformer_block_field(
                parent_key, transformer, merged_field_name, False,
            )
            for parent_key in parents
        ) if parents else False

        # set the merged value for this block
        block_structure.set_transformer_block_field(
            block_key,
            transformer,
            merged_field_name,
            (
                all_parents_merged_value or
                get_field_on_block(
                    block_structure.get_xblock(block_key), xblock_field_name,
                    False,
                )
            )
        )


def collect_merged_date_field(
        block_structure,
        transformer,
        xblock_field_name,
        merged_field_name,
        default_date,
        func_merge_parents=min,
        func_merge_ancestors=max,
):
    """
    Collects a date xBlock field of name xblock_field_name
    for the given block_structure and transformer.  The date
    value is percolated down the hierarchy of the block_structure
    and stored as a value of merged_field_name in the
    block_structure.
    """

    for block_key in block_structure.topological_traversal():

        parents = block_structure.get_parents(block_key)
        block_date = get_field_on_block(block_structure.get_xblock(block_key), xblock_field_name)
        if not parents:
            # no parents so just use value on block or default
            merged_date_value = block_date or default_date

        else:
            # compute merged value of date from all parents
            merged_all_parents_date = func_merge_parents(
                block_structure.get_transformer_block_field(
                    parent_key, transformer, merged_field_name, default_date,
                )
                for parent_key in parents
            )

            if not block_date:
                # no value on this block so take value from parents
                merged_date_value = merged_all_parents_date

            else:
                # compute merged date of the block and the parent
                merged_date_value = func_merge_ancestors(merged_all_parents_date, block_date)

        block_structure.set_transformer_block_field(
            block_key,
            transformer,
            merged_field_name,
            merged_date_value
        )
