from xml.etree.ElementTree import Element

from xml.etree import cElementTree as eTree

from messagebus import (
    MessageBus,
    Message,
    DataType,
    DefaultToken,
)
from typing import (
    Optional,
)
from .token import (
    TK_POS_GET_MODEL,
)


def requires_model(f):
    def wrapper(*args, **kwargs):
        if args[0].model is None:
            args[0].model = args[0]._retrieve_new_model()

        return f(*args, **kwargs)

    return wrapper


class PosService(object):

    def __init__(
        self,               # type: PosService
        message_bus,        # type: MessageBus
        pos_id,             # type: int
    ):
        # type: (...) -> None

        self.message_bus = message_bus
        self.pos_id = pos_id

        self.component_name = "POS{}".format(self.pos_id)

        self.model = None

    def get_model(self):
        # type: (...) -> Element

        if self.model is None:
            self.model = self._retrieve_new_model()

        return self.model

    def get_updated_model(self):
        # type: (...) -> Element

        self.model = self._retrieve_new_model()
        return self.model

    @requires_model
    def get_operator_session(self):
        # type: (...) -> Optional[str]

        for op in self.model.findall("Operator"):
            if op.get("state") == "LOGGEDIN":
                return op.get("sessionId")

        return None

    @requires_model
    def get_pod_type(self):
        # type: (...) -> str

        return self.model.find("WorkingMode").get("podType")

    @requires_model
    def get_pos_function(self):
        # type: (...) -> str

        return self.model.find("WorkingMode").get("posFunction")

    def _retrieve_new_model(self):
        # type: (...) -> Element

        msg = self.message_bus.send_message(
            component=self.component_name,
            message=Message(
                token=TK_POS_GET_MODEL,
                data_type=DataType.string,
                data=str(self.pos_id).encode()
            )
        )
        if msg.token != DefaultToken.TK_SYS_ACK:
            raise RuntimeError("Could not retrieve state of pos '{}'".format(self.pos_id))

        return eTree.XML(msg.data)
