# Copyright (c) 2018-2020, NVIDIA CORPORATION.  All rights reserved.
#
# NVIDIA CORPORATION and its licensors retain all intellectual property
# and proprietary rights in and to this software, related documentation
# and any modifications thereto.  Any use, reproduction, disclosure or
# distribution of this software and related documentation without an express
# license agreement from NVIDIA CORPORATION is strictly prohibited.
#

__all__ = ["GraphNodeLayout", "GraphNodeDescription", "GraphPortDescription", "GraphConnectionDescription", "AbstractGraphNodeDelegate"]

from enum import Enum, auto


class GraphNodeLayout(Enum):
    LIST = auto()
    COLUMNS = auto()
    HEAP = auto()


class GraphNodeDescription:
    """The object that holds the main attributes of the node"""

    def __init__(self, node, connected_source=None, connected_target=None):
        self.node = node
        self.connected_source = connected_source
        self.connected_target = connected_target


class GraphPortDescription:
    """The object that holds the main attributes of the port"""

    def __init__(
        self, port, level, relative_position, parent_child_count, connected_source=None, connected_target=None
    ):
        self.port = port
        self.level = level
        self.relative_position = relative_position
        self.parent_child_count = parent_child_count
        self.connected_source = connected_source
        self.connected_target = connected_target


class GraphConnectionDescription:
    """The object that holds the main attributes of the connection"""

    def __init__(self, node, port, widget, level, is_tangent_reversed=False):
        self.node = node
        self.port = port
        self.widget = widget
        self.level = level
        self.is_tangent_reversed = is_tangent_reversed


class AbstractGraphNodeDelegate:
    """
    The delegate generates widgets that together form the node using the
    model. The following figure shows the LIST layout of the node. For every
    zone, there is a method that is called to build this zone.

    ::

        +-------------------------+
        |     node_background     |
        | +---+-------------+---+ |
        | |[A]| node_header |[B]| |
        | +---+-------------+---+ |
        | |[C]|    port     |[D]| |
        | +---+-------------+---+ |
        | |[D]|    port     |[D]| |
        | +---+-------------+---+ |
        | |[E]| node_footer |[F]| |
        | +---+-------------+---+ |
        +-------------------------+

    COLUMN layout allows to put input and output ports at the same line:

    ::

        +-------------------------+
        |     node_background     |
        | +---+-------------+---+ |
        | |[A]| node_header |[B]| |
        | +---+------+------+---+ |
        | |[C]| port | port |[D]| |
        | |   |      |------+---| |
        | |---+------| port |[D]| |
        | |[D]| port |      |   | |
        | +---+------+------+---+ |
        | |[E]| node_footer |[F]| |
        | +---+-------------+---+ |
        +-------------------------+

    ::
    
        [A] node_header_input
        [B] node_header_output
        [C] port_input
        [D] port_output
        [E] node_footer_input (TODO)
        [F] node_footer_output (TODO)
    """

    def destroy(self):
        pass

    def get_node_layout(self, model, node_desc: GraphNodeDescription):
        """Called to determine the node layout"""
        return GraphNodeLayout.LIST

    def node_background(self, model, node_desc: GraphNodeDescription):
        """Called to create widgets of the node background"""
        pass

    def node_header_input(self, model, node_desc: GraphNodeDescription):
        """Called to create the left part of the header that will be used as input when the node is collapsed"""
        pass

    def node_header_output(self, model, node_desc: GraphNodeDescription):
        """Called to create the right part of the header that will be used as output when the node is collapsed"""
        pass

    def node_header(self, model, node_desc: GraphNodeDescription):
        """Called to create widgets of the top of the node"""
        pass

    def node_footer(self, model, node_desc: GraphNodeDescription):
        """Called to create widgets of the bottom of the node"""
        pass

    def port_input(self, model, node_desc: GraphNodeDescription, port_desc: GraphPortDescription):
        """Called to create the left part of the port that will be used as input"""
        pass

    def port_output(self, model, node_desc: GraphNodeDescription, port_desc: GraphPortDescription):
        """Called to create the right part of the port that will be used as output"""
        pass

    def port(self, model, node_desc: GraphNodeDescription, port_desc: GraphPortDescription):
        """Called to create the middle part of the port"""
        pass

    def connection(self, model, source_desc: GraphConnectionDescription, target_desc: GraphConnectionDescription):
        """Called to create the connection between ports"""
        pass
