from ..common import *

class TD_COAP_OBS_01(CoAPTestCase):
    """
---
TD_COAP_OBS_01:
    cfg: CoAP_CFG_BASIC
    obj: Handle resource observation with CON messages
    ref: '[OBSERVE] 1.2, 3, 4'
    pre:
        - Client supports Observe option
        - Server supports Observe option
        - Server offers an observable resource /obs which changes periodically (e.g. every 5s) which produces confirmable notifications
    seq:
    -   s: Client is requested to send to the server a confirmable GET
           request with observe option for resource /obs

    -   c:
        - 'The request sent by client contains:'
        -   - Type = 0(CON)
            - Code = 1(GET)
            - Token value = a value generated by the client
            - Observe option = empty
    -   c:
        - 'Server sends the response containing:'
        -   - Type = 2(ACK)
            - Code = 2.05(Content)
            - Content-format of the resource /obs
            - Token value = same as one found in the step 2
            - Observe option with a sequence number

    -   c:
        - 'Server sends a notification containing:'
        -   - Type = 0(CON)
            - Code = 2.05(Content)
            - Content-format =  same as one found in the step 3
            - Token value = same as one found in the step 3
            - "Observe option indicating increasing values(sequence number arithmetic modulo 2**24), unless more than 256 seconds elapsed"

    -   c:
        --   s: Client is requested to send to the server a confirmable GET
           request with observe option for resource /obs

    -   c:
        - 'The request sent by client contains:'
        -   - Type = 0(CON)
            - Code = 1(GET)
            - Token value = a value generated by the client
            - Observe option = empty
    -   c:
        - 'Server sends the response containing:'
        -   - Type = 2(ACK)
            - Code = 2.05(Content)
            - Content-format of the resource /obs
            - Token value = same as one found in the step 2
            - Observe option with a sequence number

    -   c:
        - 'Server sends a notification containing:'
        -   - Type = 0(CON)
            - Code = 2.05(Content)
            - Content-format =  same as one found in the step 3
            - Token value = same as one found in the step 3
            - "Observe option indicating increasing values(sequence number arithmetic modulo 2**24), unless more than 256 seconds elapsed"

    -   c:
        - Client sends an ACK
    -   v: Client displays the received information Client sends an ACK
    -   v: Client displays the received information
    """
    @classmethod
    @typecheck
    def get_stimulis(cls) -> list_of(Value):
        """
        Get the stimulis of this test case. This has to be be implemented into
        each test cases class.

        :return: The stimulis of this TC
        :rtype: [Value]
        """
        return [
            CoAP(type='con', code='get', opt=Opt(CoAPOptionObserve(0), CoAPOptionUriPath("obs")))
        ]

    def run(self):
        # Step 2
        self.match("client", CoAP(type="con", code="get",
        opt=self.uri("/obs", CoAPOptionObserve(0))))

        token = self.coap["tok"]

        self.next()

        # Step 3
        if not self.match("server", CoAP(type="ack", code=2.05, opt=Opt(
            CoAPOptionObserve(),
            CoAPOptionContentFormat(),
        ))):
                raise self.Stop()
                self.match("server", CoAP(tok=token), "fail")

        content_format = self.coap["opt"][CoAPOptionContentFormat]["val"]
        index          = self.coap["opt"][CoAPOptionObserve]["val"]

        # match at least 2 notifications
        for i in range(2):

            self.next()

            # Step 4
            if not self.match("server", CoAP(type="con", code=2.05, opt=Opt(
                CoAPOptionObserve(),
                CoAPOptionContentFormat(),
            ))):
                raise self.Stop()
                self.match("server", CoAP(tok=token), "fail")
                self.match("server", CoAP(opt=Opt(CoAPOptionContentFormat(content_format))), "fail")

            new_index = self.coap["opt"][CoAPOptionObserve]["val"]

            self.set_verdict(("pass" if new_index > index else "fail"),
                             "value of observe option must be increasing")

            self.next()

            # Step 6
            self.match("client", CoAP(type="ack", code=0))

        raise self.Stop()
