from __future__ import annotations

from abc import ABC, abstractmethod
from typing import Any, Dict, List, Union

from sila2.framework import Command, Feature, FullyQualifiedIdentifier, Property
from sila2.server import FeatureImplementationBase

from .lockcontroller_types import LockServer_Responses, UnlockServer_Responses


class LockControllerBase(FeatureImplementationBase, ABC):

    """
    This Feature allows a SiLA Client to lock a SiLA Server for exclusive use, preventing other SiLA Clients
    from using the SiLA Server while it is locked. To lock a SiLA Server a Lock Identifier has to be set, using the
    'LockServer' command. This Lock Identifier has to be sent along with every (lock protected)
    request to the SiLA Server in order to use its functionality.

    To send the lock identifier the SiLA Client Meta Data 'LockIdentifier' has to be used.

    When locking a SiLA Server a timeout can be specified that defines the time after which the SiLA Server will
    be automatically unlocked if no request with a valid lock identifier has been received meanwhile.
    After the timeout has expired or after explicit unlock no lock identifier has to be sent any more.
    """

    @abstractmethod
    def get_IsLocked(self, *, metadata: Dict[FullyQualifiedIdentifier, Any]) -> bool:
        """
          Returns true if the SiLA Server is currently locked or false else.

        This property MUST NOT be lock protected, so that any SiLA Client can query the current lock state
        of a SiLA Server.

          :param metadata: The SiLA Client Metadata attached to the call
          :return: Returns true if the SiLA Server is currently locked or false else.

        This property MUST NOT be lock protected, so that any SiLA Client can query the current lock state
        of a SiLA Server.
        """
        pass

    @abstractmethod
    def LockServer(
        self, LockIdentifier: str, Timeout: int, *, metadata: Dict[FullyQualifiedIdentifier, Any]
    ) -> LockServer_Responses:
        """
          Locks a SiLA Server for exclusive use by setting a lock identifier that has to be sent along with
        any following (lock protected) request as long as the SiLA Server is locked.
        The lock can be reset by issuing the 'Unlock Server' command.


          :param LockIdentifier: The lock identifier that has to be sent along with every (lock protected) request to use the server's
          functionality.

          :param Timeout: The time (in seconds) after a SiLA Server is automatically unlocked when no request with a valid lock identifier
          has been received meanwhile. A timeout of zero seconds specifies an infinite time (no timeout).

          :param metadata: The SiLA Client Metadata attached to the call

        """
        pass

    @abstractmethod
    def UnlockServer(
        self, LockIdentifier: str, *, metadata: Dict[FullyQualifiedIdentifier, Any]
    ) -> UnlockServer_Responses:
        """
          Unlocks a locked SiLA Server. No lock identifier has to be sent for any following calls until
        the server is locked again via the 'Lock Server' command.


          :param LockIdentifier: The lock identifier that has been used to lock the SiLA Server.

          :param metadata: The SiLA Client Metadata attached to the call

        """
        pass

    @abstractmethod
    def get_calls_affected_by_LockIdentifier(self) -> List[Union[Feature, Command, Property, FullyQualifiedIdentifier]]:
        """
          Returns the fully qualified identifiers of all features, commands and properties affected by the
          SiLA Client Metadata 'Delay'.

          **Description of 'LockIdentifier'**:
          The lock identifier has to be sent with every (lock protected) call in order to use the functionality
        of a locked SiLA Server.

          :return: Fully qualified identifiers of all features, commands and properties affected by the
              SiLA Client Metadata 'Delay'.
        """
        pass
