from ..bf_gbl_env.cst_env import *


def _processEntryFromControlPlane(
    self,
    op_type,
    tbl_name,
    key_field_list,
    data_field_list,
    tbl_action_name,
    key_annotation_fields,
    data_annotation_fields,
):
    try:
        tbl = self.bfgc.bfrt_info.table_get(tbl_name)

        for annotation in key_annotation_fields.keys():
            tbl.info.key_field_annotation_add(
                annotation, key_annotation_fields[annotation]
            )

        for annotation in data_annotation_fields.keys():
            tbl.info.data_field_annotation_add(
                annotation, tbl_action_name, data_annotation_fields[annotation]
            )

        key_list = [tbl.make_key(key_field_list)]
        data_list = [tbl.make_data(data_field_list, tbl_action_name)]

    except KeyError as e:
        (str_key, str_data) = _formatErrMessage(key_field_list, data_field_list)
        err_msg = (
            "dataplane-say entry failed to prepare entry for table %s with Key[%s] Data[%s]\n"
            % (tbl_name, str_key, str_data)
        )
        logger.warning(err_msg)
        self.file_w.write(err_msg)
        self.file_w.flush()
        return

    try:
        if op_type == WRITE:
            tbl.entry_add(self.bfgc.target, key_list, data_list)
            logger.debug(
                "Writing entry in table:%s keys:%s act_param:%s",
                tbl_name,
                key_list,
                data_list,
            )
        elif op_type == UPDATE:
            tbl.entry_mod(self.bfgc.target, key_list, data_list)
            logger.debug(
                "Updating entry in table:%s keys:%s act_param:%s",
                tbl_name,
                key_list,
                data_list,
            )
        elif op_type == DELETE:
            tbl.entry_del(self.bfgc.target, key_list)
            logger.debug(
                "Deleting entry in table:%s keys:%s act_param:%s",
                tbl_name,
                key_list,
                data_list,
            )
        else:
            print("Error op_type unknown")

    except gc.BfruntimeRpcException as e:
        (str_key, str_data) = _formatErrMessage(key_field_list, data_field_list)
        err_msg = (
            "dataplane-say entry failed to program %s entry for table %s with Key[%s] Data[%s]\n"
            % (op_type, tbl_name, str_key, str_data)
        )
        logger.warning(err_msg)
        self.file_w.write(err_msg)
        self.file_w.flush()

    except grpc.RpcError as e:
        (str_key, str_data) = _formatErrMessage(key_field_list, data_field_list)
        err_msg = (
            "dataplane-say entry failed to program %s entry via GRPC for table %s with Key[%s] Data[%s]\n"
            % (op_type, tbl_name, str_key, str_data)
        )
        logger.warning(err_msg)
        self.file_w.write(err_msg)
        self.file_w.flush()


def _formatErrMessage(key_field_list, data_field_list):
    str_key = ""
    for key_tuple in key_field_list:
        if str_key != "":
            str_key = (
                str_key
                + ","
                + str(key_tuple.name)
                + " "
                + str(key_tuple.value)
                + " "
                + str(key_tuple.mask)
                + " "
                + str(key_tuple.prefix_len)
                + " "
                + str(key_tuple.low)
                + " "
                + str(key_tuple.low)
                + " "
                + str(key_tuple.is_valid)
            )
        else:
            str_key = (
                str(key_tuple.name)
                + " "
                + str(key_tuple.value)
                + " "
                + str(key_tuple.mask)
                + " "
                + str(key_tuple.prefix_len)
                + " "
                + str(key_tuple.low)
                + " "
                + str(key_tuple.low)
                + " "
                + str(key_tuple.is_valid)
            )

    str_data = ""
    for data_tuple in data_field_list:
        if str_data != "":
            str_data = (
                str_data
                + ","
                + str(data_tuple.name)
                + " "
                + str(data_tuple.val)
                + " "
                + str(data_tuple.float_val)
                + " "
                + str(data_tuple.str_val)
                + " "
                + str(data_tuple.bool_val)
                + " "
                + str(data_tuple.int_arr_val)
                + " "
                + str(data_tuple.str_arr_val)
                + " "
                + str(data_tuple.container_arr_val)
            )
        else:
            str_data = (
                str(data_tuple.name)
                + " "
                + str(data_tuple.val)
                + " "
                + str(data_tuple.float_val)
                + " "
                + str(data_tuple.str_val)
                + " "
                + str(data_tuple.bool_val)
                + " "
                + str(data_tuple.int_arr_val)
                + " "
                + str(data_tuple.str_arr_val)
                + " "
                + str(data_tuple.container_arr_val)
            )
    return (str_key, str_data)
