# Path: pif_ir/bir/objects/control_state.py
# class ControlState(object):
#     def __init__(self, control_state_attr, header, bir_parser):
#         # control_state format:
#         #   - [[cond, new_offset], [,], [,], ..., default_offset]
#         #   - [[cond, new_bb], [,], [,], ..., default_bb]
#         self.offset = control_state_attr[0]
#         self.basic_block = control_state_attr[1]
#         self.header = header
#         self.bir_parser = bir_parser
# 
#     def _get_offset(self, packet, bit_offset):
#         for cond in self.offset:
#             if isinstance(cond, str) or isinstance(cond, int):
#                 return self.bir_parser.eval_inst(cond, self.header, packet,
#                                                  bit_offset)
#             elif self.bir_parser.eval_cond(cond[0], self.header, packet,
#                                            bit_offset):
#                 return self.bir_parser.eval_inst(cond[1], self.header, packet,
#                                                  bit_offset)
#         raise BIRError("didn't find offset!")
# 
#     def _get_basic_block(self, packet, bit_offset):
#         for cond in self.basic_block:
#             if isinstance(cond, str):
#                 return cond
#             elif self.bir_parser.eval_cond(cond[0], self.header, packet,
#                                            bit_offset):
#                 return cond[1]
#         raise BIRError("didn't find basic_block!")
# 
#     def process(self, packet, bit_offset):
#         offset = self._get_offset(packet, bit_offset)
#         basic_block = self._get_basic_block(packet, bit_offset)
#         if basic_block == "$done$":
#             basic_block = None
#         return offset, basic_block
# 
# Path: pif_ir/bir/objects/processor.py
# class Processor(object):
#     def __init__(self, name, next_processor=None):
#         self.name = name
#         self.next_processor = next_processor
# 
#     def process(self, packet, bit_offset=0):
#         msg = "Processor {}: does not implement process()".format(self.name)
#         raise BIRError(msg)
# 
# Path: pif_ir/bir/utils/validate.py
# def check_attributes(obj_name, attributes, required_attributes):
#     for attr in required_attributes:
#         if attr not in attributes:
#             raise BIRYamlAttrError(attr, obj_name)
# 
# Path: pif_ir/bir/utils/validate.py
# def check_control_state(obj_name, control_state_attributes):
#     # has only 2 attributes (i.e. offset, basic_block)
#     if len(control_state_attributes) != 2:
#         raise BIRControlStateError(obj_name, "expecting 2 attributes")
# 
#     # offset conditions format must be [cond, offset]
#     # must have a default offset (not required to be the last!)
#     default_offset = False
#     for cond in control_state_attributes[0]:
#         if isinstance(cond, list) and len(cond) == 2:
#             pass
#         elif isinstance(cond, str) or isinstance(cond, int):
#             default_offset = True
#         else:
#             msg = "unexpected offset condition: {}".format(cond)
#             raise BIRControlStateError(obj_name, msg)
#     if not default_offset:
#         raise BIRControlStateError(obj_name, "missing default offset")
# 
#     # basic_block conditions format must be [cond, basic_block]
#     # must have a default basic_block (not required to be the last!)
#     default_bb = False
#     for cond in control_state_attributes[1]:
#         if isinstance(cond, list) and len(cond) == 2:
#             pass
#         elif isinstance(cond, str):
#             default_bb = True
#         else:
#             msg = "unexpected basic_block condition: {}".format(cond)
#             raise BIRControlStateError(obj_name, msg)
#     if not default_bb:
#         raise BIRControlStateError(obj_name, "missing default basic block")


import logging
from pif_ir.bir.objects.control_state import ControlState
from pif_ir.bir.objects.processor import Processor
from pif_ir.bir.utils.validate import check_attributes
from pif_ir.bir.utils.validate import check_control_state



class ControlFlow(Processor):
    """
    @brief Class for a control flow object

    @param name The name of the control flow AIR object
    @param air_control_flow_attrs The attributes of the control_flow AIR object
    @param first_packet_offset The first packet offset
    @param first_basic_block The first basic block
    """
    required_attributes = ['start_control_state']
    def __init__(self, name, control_flow_attrs, basic_blocks, bir_parser):
        super(ControlFlow, self,).__init__(name)
        check_attributes(name, control_flow_attrs, 
                         ControlFlow.required_attributes)
        logging.debug("Adding Control Flow {0}".format(name))

        self.basic_blocks = basic_blocks

        cf = control_flow_attrs['start_control_state']

# Path: pif_ir/bir/objects/control_state.py
# class ControlState(object):
#     def __init__(self, control_state_attr, header, bir_parser):
#         # control_state format:
#         #   - [[cond, new_offset], [,], [,], ..., default_offset]
#         #   - [[cond, new_bb], [,], [,], ..., default_bb]
#         self.offset = control_state_attr[0]
#         self.basic_block = control_state_attr[1]
#         self.header = header
#         self.bir_parser = bir_parser
# 
#     def _get_offset(self, packet, bit_offset):
#         for cond in self.offset:
#             if isinstance(cond, str) or isinstance(cond, int):
#                 return self.bir_parser.eval_inst(cond, self.header, packet,
#                                                  bit_offset)
#             elif self.bir_parser.eval_cond(cond[0], self.header, packet,
#                                            bit_offset):
#                 return self.bir_parser.eval_inst(cond[1], self.header, packet,
#                                                  bit_offset)
#         raise BIRError("didn't find offset!")
# 
#     def _get_basic_block(self, packet, bit_offset):
#         for cond in self.basic_block:
#             if isinstance(cond, str):
#                 return cond
#             elif self.bir_parser.eval_cond(cond[0], self.header, packet,
#                                            bit_offset):
#                 return cond[1]
#         raise BIRError("didn't find basic_block!")
# 
#     def process(self, packet, bit_offset):
#         offset = self._get_offset(packet, bit_offset)
#         basic_block = self._get_basic_block(packet, bit_offset)
#         if basic_block == "$done$":
#             basic_block = None
#         return offset, basic_block
# 
# Path: pif_ir/bir/objects/processor.py
# class Processor(object):
#     def __init__(self, name, next_processor=None):
#         self.name = name
#         self.next_processor = next_processor
# 
#     def process(self, packet, bit_offset=0):
#         msg = "Processor {}: does not implement process()".format(self.name)
#         raise BIRError(msg)
# 
# Path: pif_ir/bir/utils/validate.py
# def check_attributes(obj_name, attributes, required_attributes):
#     for attr in required_attributes:
#         if attr not in attributes:
#             raise BIRYamlAttrError(attr, obj_name)
# 
# Path: pif_ir/bir/utils/validate.py
# def check_control_state(obj_name, control_state_attributes):
#     # has only 2 attributes (i.e. offset, basic_block)
#     if len(control_state_attributes) != 2:
#         raise BIRControlStateError(obj_name, "expecting 2 attributes")
# 
#     # offset conditions format must be [cond, offset]
#     # must have a default offset (not required to be the last!)
#     default_offset = False
#     for cond in control_state_attributes[0]:
#         if isinstance(cond, list) and len(cond) == 2:
#             pass
#         elif isinstance(cond, str) or isinstance(cond, int):
#             default_offset = True
#         else:
#             msg = "unexpected offset condition: {}".format(cond)
#             raise BIRControlStateError(obj_name, msg)
#     if not default_offset:
#         raise BIRControlStateError(obj_name, "missing default offset")
# 
#     # basic_block conditions format must be [cond, basic_block]
#     # must have a default basic_block (not required to be the last!)
#     default_bb = False
#     for cond in control_state_attributes[1]:
#         if isinstance(cond, list) and len(cond) == 2:
#             pass
#         elif isinstance(cond, str):
#             default_bb = True
#         else:
#             msg = "unexpected basic_block condition: {}".format(cond)
#             raise BIRControlStateError(obj_name, msg)
#     if not default_bb:
#         raise BIRControlStateError(obj_name, "missing default basic block")


# Path: pif_ir/bir/objects/control_flow.py
import logging
from pif_ir.bir.objects.control_state import ControlState
from pif_ir.bir.objects.processor import Processor
from pif_ir.bir.utils.validate import check_attributes
from pif_ir.bir.utils.validate import check_control_state




class ControlFlow(Processor):
    """
    @brief Class for a control flow object

    @param name The name of the control flow AIR object
    @param air_control_flow_attrs The attributes of the control_flow AIR object
    @param first_packet_offset The first packet offset
    @param first_basic_block The first basic block
    """
    required_attributes = ['start_control_state']
    def __init__(self, name, control_flow_attrs, basic_blocks, bir_parser):
        super(ControlFlow, self,).__init__(name)
        check_attributes(name, control_flow_attrs, 
                         ControlFlow.required_attributes)
        logging.debug("Adding Control Flow {0}".format(name))

        self.basic_blocks = basic_blocks

        cf = control_flow_attrs['start_control_state']

        check_control_state(self.name, cf)