1"""
 2The classes Limits and LimitDefinition represent the contents
 3of the SRDB limits tables OCF and OCP.
 4"""
 5
 6import logging
 7
 8OCF_COLUMN_COUNT = 5
 9OCP_COLUMN_COUNT = 6
10logger = logging.getLogger()
11
12
13class Limits:
14    """
15    Representation of a 'monitoring parameter checks' table (OCF) entry.
16
17    Raises:
18        ValueError: On incorrect number of OCF/OCP list entries.
19    """
20
21    def __init__(self, ocf_entry, ocp_entries=None):
22        """ Initializes Limits with an OCF entry as a list
23            and optionally multiple OCP entries as nested lists ordered by OCP_POS.
24        :param ocf_entry: [OCF_NAME, OCF_NBCHCK, OCF_NBOOL, OCF_INTER, OCF_CODIN]
25        :param ocp_entries: [[OCP_NAME, OCP_POS, OCP_TYPE, OCP_LVALU, OCP_HVALU, OCP_RLCHK, OCP_VALPAR], ...]
26        """
27        if len(ocf_entry) != OCF_COLUMN_COUNT:
28            raise ValueError(f"The OCP entry doesn't contain {OCF_COLUMN_COUNT} expected columns.")
29
30        self.name = ocf_entry[0]
31        self.nbchck = int(ocf_entry[1])
32        self.nbool = int(ocf_entry[2])
33        self.inter = ocf_entry[3]
34        self.codin = ocf_entry[4]
35        self.ocp = []
36
37        if ocp_entries:
38            if self.nbool != len(ocp_entries):
39                logger.warning(f"The number of OCP entries ({len(ocp_entries)}) of '{self.name}' "
40                                f"doesn't match the NBOOL value ({self.nbool}).")
41
42            for ocp_entry in ocp_entries:
43                self.ocp.append(LimitDefinition(ocp_entry, self.codin))
44            self.ocp.sort(key=lambda entry: entry.pos)
45
46    def __repr__(self):
47        return f"Limits([{self.name}, {self.nbchck}, {self.nbool}, {self.inter}, {self.codin}])"
48
49
50class LimitDefinition:
51    """
52    Representation of a monitoring checks definition table (OCP) entry.
53
54    Raises:
55            ValueError: On incorrect number of OCP list entries.
56    """
57
58    def __init__(self, ocp_entry, codin):
59        """
60        Initializes a LimitDefinition with an OCP entry as a list
61        and a value interpretation field OCF_CODIN.
62        :param ocp_entry: [OCP_POS, OCP_TYPE, OCP_LVALU, OCP_HVALU, OCP_RLCHK, OCP_VALPAR]
63        :param codin: The interpretation of LVALU/HVALU: (I)nt, (R)eal or (A)SCII
64        """
65        if len(ocp_entry) != OCP_COLUMN_COUNT:
66            raise ValueError(f"The OCP entry doesn't contain {OCP_COLUMN_COUNT} expected columns.")
67
68        self.pos = int(ocp_entry[0])
69        self.type = ocp_entry[1]
70        self.rlchk = ocp_entry[4]
71        # Validity check is optional, rlchk parameter might be empty
72        if self.rlchk != '':
73            self.valpar = int(ocp_entry[5])
74        else:
75            self.valpar = None
76        self._set_limit_values(codin, ocp_entry[2], ocp_entry[3])
77
78    def _set_limit_values(self, codin, lvalu, hvalu):
79        """ Set high/low limit values and types according to the type interpretation OCF_CODIN. """
80        if codin == 'I':
81            self.lvalu = int(lvalu) if lvalu else lvalu
82            self.hvalu = int(hvalu) if hvalu else hvalu
83        elif codin == 'R':
84            self.lvalu = float(lvalu) if lvalu else lvalu
85            self.hvalu = float(hvalu) if hvalu else hvalu
86        else:
87            self.lvalu = lvalu
88            self.hvalu = hvalu
89
90    def __repr__(self):
91        return f"LimitDefinition([{self.pos}, {self.type}, " \
92                f"{self.lvalu}, {self.hvalu}, " \
93                f"{self.rlchk}, {self.valpar}])"