
from .switcher import SwitcherNode
from ebu_tt_live.documents import EBUTT3Document, EBUTT3DocumentSequence


class HandoverNode(SwitcherNode):
    """
    The handover node implements the functionality described in EBU-3370. It is a specialised case
    of the switching node basing its decisions on the handover-related attributes on the document root element and
    on its previous decisions.
    """

    _expects = EBUTT3Document
    _provides = EBUTT3Document
    _sequence_identifier = None
    _authors_group_identifier = None
    _current_token = None
    _current_selected_input_sequence_id = None
    _last_sequence_number = None
    _known_sequences = None

    def __init__(self, node_id, authors_group_identifier, sequence_identifier, consumer_carriage=None, producer_carriage=None, **kwargs):
        super(HandoverNode, self).__init__(
            node_id=node_id,
            consumer_carriage=consumer_carriage,
            producer_carriage=producer_carriage,
            **kwargs
        )
        self._authors_group_identifier = authors_group_identifier
        self._sequence_identifier = sequence_identifier
        self._current_sequence_id = None
        self._last_sequence_number = 0
        self._known_sequences = {}

    def process_document(self, document, **kwargs):
        """
        The specified functionality is met by keeping the following priorities in mind when processing an
        incoming document:

          - If this is a new sequence_identifier+sequence_number pair and
            authorsGroupIdentifier+authorsGroupControlToken are defined and authorsGroupIdentifier matches the
            configuration

            - If sequenceIdentifier matches the one selected the document should be emitted
            - If sequenceIdentifier does not match the one selected or one is not selected

              - If the token is higher than our current one or one is not set the document should be emitted
              - If token is lower than the our current one or missing the document should be ignored

            - If the document should be emitted

              - Set/update current sequenceIdentifier in the node from the one in the document
              - Set/update current authorsGroupControlToken in the node
              - Reassign document to output sequenceIdentifier
              - Assign new sequenceNumber to document
              - Emit document


        :param document:
        :param kwargs:

        """
        emit = False

        if self.is_document(document):
            # This step is necessary to ensure that the authors group does not change in a sequence
            self._known_sequences.setdefault(
                document.sequence_identifier, EBUTT3DocumentSequence.create_from_document(document=document)
            ).is_compatible(document=document)
            if self.check_if_document_seen(document=document) is True \
                    and document.authors_group_identifier == self._authors_group_identifier \
                    and document.authors_group_control_token is not None:
                if self._current_token is None or self._current_token < document.authors_group_control_token:
                    # Switch input
                    self._current_selected_input_sequence_id = document.sequence_identifier
                    emit = True
                elif self._current_selected_input_sequence_id == document.sequence_identifier:
                    emit = True

            if emit is True:
                # Update token
                self._current_token = document.authors_group_control_token  # So are we going to error here?
                self._last_sequence_number += 1

                document.authors_group_selected_sequence_identifier = document.sequence_identifier
                document.sequence_identifier = self._sequence_identifier
                document.sequence_number = self._last_sequence_number
                self.producer_carriage.emit_data(
                    data=document,
                    **kwargs
                )
        else:
            document.sequence_identifier = self._sequence_identifier
            self.producer_carriage.emit_data(
                data=document,
                **kwargs
            )
