from abc import ABC
from typing import Any, AnyStr, List, Tuple

from leo_grifo_common import TestCommonInterface,get_json_config
from brainbox_interface import *
import logging


class BrainBoxInterface(TestCommonInterface, ABC):
    def __init__(self, _timeout=0.5):
        super().__init__(_timeout)
        conf = get_json_config()
        brainbox_conf = conf.get("brainbox",{})
        self.__device = int(brainbox_conf.get("device","1"))
        self.__addr = brainbox_conf.get("address","192.168.127.254")
        self.__port = int(brainbox_conf.get("port","9500"))
        self.__discretes = brainbox_conf.get("discretes",[])
        self.__brain_box = BrainboxInterface(self.__addr, self.__port, _timeout)
        self.__io_values = 0x0

    def __index( self, label ):
        for i in range(len(self.__discretes)):
            if label in self.__discretes[i]:
                return i
        return -1
    
    def check(self, expected_result, *fields, **kwargs) -> (bool, Any, AnyStr):
        value, error = self.get(*fields,**kwargs)
        if error:
            return False,value, error   
        ret = False        
        if value is not None:
            if expected_result in ( "OFF" , False, 0, "0" ):
                expected_result_value = True          
            elif expected_result in ( "ON" , True, 1, "1" ):
                expected_result_value = False   
            else:
                return False, f'Invalid value {expected_result}' 
            ret = value == expected_result
        return ret, value, error

    def set(self, value, *fields, **kwargs) -> (bool, AnyStr):        
        if len(fields) != 1:
            return False, f'missing required discrete name as argument'
        discrete_pos = self.__index( fields[0] )
        if discrete_pos < 0:
            return False, f'discrete name not found'  
        discrete_val = 1 << discrete_pos
        if value in ( "OFF" , False, 0, "0" ):
            self.__io_values = self.__io_values & ~discrete_val           
        elif value in ( "ON" , True, 1, "1" ):
            self.__io_values = self.__io_values | discrete_val   
        else:
            return False, f'Invalid value {value}'
        logging.info(f'{discrete_val} {discrete_pos}')
        cmd = f'@{self.__device:02X}{self.__io_values:02X}\r\n'
        logging.info(cmd)
        ret, value, error = self.__brain_box.send_data(cmd)
        return ret,error

    def get(self,*fields, **kwargs) -> (Any, AnyStr):
        if len(fields) != 1:
            return False, f'missing required discrete name as argument'
        discrete_pos = self.__index( fields[0] )
        if discrete_pos < 0:
            return False, f'discrete name not found'  
        discrete_val = 1 << 8 + discrete_pos
        #get all data
        cmd = f'@{self.__device:02X}\r\n'
        logging.info(cmd)
        ret, str_all_value, error = self.__brain_box.send_data(cmd)
        all_value = int(str_all_value.strip()[1:],16)
        logging.info(f'{all_value} {discrete_val} {discrete_pos}')
        bin_value=(all_value & discrete_val) > discrete_pos 
        value = int(bin_value) == 1 
        return value, error


theBrainBox = BrainBoxInterface(2)
