import pymfx4.mfdatastorage as ds
from pymfx4.mffullindex import FullIndex
from pymfx4 import mfl

import time
import re



class mfparameters:
    """A list of parameters to be send.

    Loads a list of parameters from a textfile usually generated by the MFX_4 Explorer."""

    def __init__(self, config, tim=5):
        """Loads a list of parameters from a textfile <config>."""
        self.config = config
        self.Parameters = {}
        self.load_parameters()

    def load_parameters(self):
        mfl.info(f"Loading {self.config} as Script-File.")
        line = 0
        for x in [line.rstrip('\n') for line in open(self.config)]:
            matchObj = re.match(r'(?P<cmd>.*?)_(?P<nodeid>.*?)_(?P<index>.*?)_(?P<subindex>.*?)_(?P<content>.*)`(?P<description>.*)', x, re.I | re.DOTALL)
            if matchObj:
                fi = FullIndex(int(matchObj.group("nodeid")), int(matchObj.group("index")), int(matchObj.group("subindex")))
                content = matchObj.group("content")
                description = matchObj.group("description").strip()
                fi.NodeId = 0
                self.Parameters[fi] = [content, description]
            else:
                mfl.info(f"Could not load line:{line}.")
            line += 1
        pass


class mfParameterManager:
    """Static class to read / write and check mfparameters."""

    def Check(Package, Endpoint=None):
        Node = Endpoint._Node if Endpoint is not None else 0
        for entry in Package.Parameters:
            e = entry.Node(Node)
            ds.storage.Get(e)
            mfl.info(f"get {e}")
            time.sleep(0.1)

        time.sleep(0.5)
        OKn = 0
        FAILn = 0
        for entry in Package.Parameters:

            e = entry.Node(Node)

            soll_val = Package.Parameters[entry][0] if Package.Parameters[entry][0] is None else Package.Parameters[entry][0].lower().rstrip("\x00")
            ist_val = ds.storage.Structure[e].Value if ds.storage.Structure[e].Value is None else ds.storage.Structure[e].Value.lower().rstrip("\x00")

            if ds.storage.Structure[e].DataType is None:
                mfl.error(f"{e} has no DataType ")

            soll_native_val = None if soll_val is None or ds.storage.Structure[e].DataType is None else ds.storage.Structure[e].DataType(soll_val)
            ist_native_val = ds.storage.Structure[e].NativeValue()

            oOK = (soll_val == ist_val or soll_native_val == ist_native_val) and soll_val is not None and ist_val is not None

            # stringOK = "OK"
            if oOK:
                OKn = OKn + 1
            else:
                # stringOK = "FAIL"
                FAILn = FAILn + 1

            # soll = "<None>" if Package.Parameters[entry][0] is None else soll_val
            # ist = "<None>" if ds.storage.Structure[e].Value is None else ist_val

            if ist_native_val is not None and soll_native_val is not None:
                mfl.info("{stringOK:5} {e} {soll_native_val:>20} == {ist_native_val:>20}")
            else:
                mfl.info("{stringOK:5} {e} {soll:>20} == {ist:20}")

        mfl.info(" OK:{OKn:4}  FAILED:{FAILn:4} ")
        return mfParameterManager.CheckOK((OKn, FAILn))

    def Deploy(Package, Endpoint=None):
        Node = Endpoint._Node if Endpoint is not None else 0
        for entry in Package.Parameters:
            e = entry.Node(Node)
            ds.storage.Set(e, Package.Parameters[entry][0])
            mfl.info(f"set {e}")

    def DeployAndCheck(Package, Endpoint=None):
        # Node = Endpoint._Node if Endpoint != none else 0
        mfParameterManager.Deploy(Package, Endpoint)
        time.sleep(1)
        return mfParameterManager.Check(Package, Endpoint)

    def DeployAndCheckEntrywise(Package, Endpoint=None):
        Node = Endpoint._Node if Endpoint is not None else 0
        OKn = 0
        FAILn = 0
        for entry in Package.Parameters:
            e = entry.Node(Node)
            ds.storage.Get(e)
            mfl.info(f"get {e}")
            time.sleep(0.1)

            ds.storage.Set(e, Package.Parameters[entry][0])
            mfl.info(f"set {e}")
            time.sleep(3)

            ds.storage.Get(e)
            mfl.info(f"get {e}")
            time.sleep(0.1)

            soll_val = Package.Parameters[entry][0] if Package.Parameters[entry][0] is None else Package.Parameters[entry][0].lower().rstrip("\x00")
            ist_val = ds.storage.Structure[e].Value if ds.storage.Structure[e].Value is None else ds.storage.Structure[e].Value.lower().rstrip("\x00")

            if ds.storage.Structure[e].DataType is None:
                mfl.error(f"{e} has no DataType ")

            soll_native_val = None if soll_val is None or ds.storage.Structure[e].DataType is None else ds.storage.Structure[e].DataType(soll_val)
            ist_native_val = ds.storage.Structure[e].NativeValue()

            oOK = (soll_val == ist_val or soll_native_val == ist_native_val) and soll_val is not None and ist_val is not None

            # stringOK = "OK"
            if oOK:
                OKn = OKn + 1
            else:
                # stringOK = "FAIL"
                FAILn = FAILn + 1

            # soll = "<None>" if Package.Parameters[entry][0] is None else soll_val
            # ist = "<None>" if ds.storage.Structure[e].Value is None else ist_val

            if ist_native_val is not None and soll_native_val is not None:
                mfl.info("{stringOK:5} {e} {soll_native_val:>20} == {ist_native_val:<20}")
            else:
                mfl.info("{stringOK:5} {e} {soll:>20} == {ist:<20}")

        mfl.info("RESULT OK:{OKn:4}  FAILED:{FAILn:4} ")
        return mfParameterManager.CheckOK((OKn, FAILn))

    def CheckOK(val):
        if val is None:
            return None
        ok, fail = val
        return fail == 0
