from .events import Events
from .nodes import Node
from .time import Time
from .display import Display

class StateMachineError(Exception):
    pass


# This is the main, active state (Node).
_ACTIVE_STATE = None

# In some cases, the previous state isn't totally shut down, but temporarily put on hold.
# Only the _render() call will be made on hold states.
_HOLD_STATE = None

# List of all states registered into the State Manager.
_STATE_LIST = []

_TIME = Time()


class StateMachine:
    def __init__(self):
        pass

    def has_node(self, name):
        """
        Returns true if a Node with the given name has been registered in the State List.
        NOTE: This is only going to check the root Node's name, not any other node in the node tree.
        """
        global _STATE_LIST
        for n in _STATE_LIST:
            if n.name == name:
                return True
        return False

    def register_node(self, node):
        """

        """
        if not isinstance(node, Node):
            raise TypeError("Expected a Node instance.")
        # Check if given the root Node. If not, get the root Node.
        if node.parent != None:
            node = node.root
        if self.has_node(node.name):
            raise StateMachineError("State machine already registered node named '{}'. Names must be unique.".format(node.name))
        global _STATE_LIST
        _STATE_LIST.append(node)

    def activate_node(self, name, hold_previous=False):
        """

        """
        global _ACTIVE_STATE, _TIME
        if self.has_node(name):
            if _ACTIVE_STATE is not None:
                if _ACTIVE_STATE.name == name:
                    return
                self._releaseActive(hold_previous)
            self._setActive(name)
            if _ACTIVE_STATE is not None:
                _TIME.reset()


    def _relaseActive(self, hold_previous):
        global _ACTIVE_STATE, _HOLD_STATE
        a = _ACTIVE_STATE
        a._pause()
        if _HOLD_STATE is not None:
            _ACTIVE_STATE = _HOLD_STATE
            _HOLD_STATE = None
            _ACTIVE_STATE._start()
        else:
            _ACTIVE_STATE = None
        
        if hold_previous == True:
            _HOLD_STATE = a
        else:
            a._close()

    def _setActive(self, name):
        global _ACTIVE_STATE, _STATE_LIST
        for n in _STATE_LIST:
            if n.name == name:
                _ACTIVE_STATE = n
                break
        if _ACTIVE_STATE is not None:
            _ACTIVE_STATE._init()
            _ACTIVE_STATE._start()
        elif _HOLD_STATE is not None:
            # If we failed to find an Active state, then we need to drop any hold state as well...
            # Keep things as clean as possible
            _HOLD_STATE._close()
            _HOLD_STATE = None

    def close(self):
        global _ACTIVE_STATE, _HOLD_STATE, _STATE_LIST
        if _HOLD_STATE is not None:
            _HOLD_STATE._close()
            _HOLD_STATE = None
        if _ACTIVE_STATE is not None:
            _ACTIVE_STATE._pause()
            _ACTIVE_STATE._close()
            _ACTIVE_STATE = None
        _STATE_LIST = []

    def update(self):
        global _ACTIVE_STATE, _TIME
        if _ACTIVE_STATE is not None:
            _ACTIVE_STATE._update(_TIME.delta)

    def render(self):
        global _ACTIVE_STATE, _HOLD_STATE
        dsurf = Display.surface
        if dsurf is not None:
            Display.clear()

            # If there's a hold state, render that first.
            if _HOLD_STATE is not None:
                _HOLD_STATE._render(dsurf)
            # Render the active state next so it overdraws the hold state.
            if _ACTIVE_STATE is not None:
                _ACTIVE_STATE._render(dsurf)

            Display.flip()