
import random
import logging
import os

import claripy

from ...sim_type import SimTypeFunction, SimTypeInt
from ... import sim_options as so
from ... import SIM_LIBRARIES
from ... import BP_BEFORE, BP_AFTER
from ...storage.file import SimFile, SimFileDescriptor
from ...state_plugins import SimSystemPosix
from ...errors import AngrCallableMultistateError, AngrCallableError, AngrError, SimError
from .custom_callable import IdentifierCallable


l = logging.getLogger(name=__name__)

flag_loc = str(os.path.join(os.path.dirname(os.path.realpath(__file__)), '../example_flag_page'))
try:
    with open(flag_loc, "rb") as f:
        FLAG_DATA = f.read()
except IOError:
    FLAG_DATA = b"A"*0x1000

assert len(FLAG_DATA) == 0x1000


class Runner(object):
    def __init__(self, project, cfg):
        # this is kind of fucked up
        project.simos.syscall_library.update(SIM_LIBRARIES['cgcabi_tracer'])

        self.project = project
        self.cfg = cfg
        self.base_state = None

    def _get_recv_state(self):
        try:
            options = set()
            options.add(so.CGC_ZERO_FILL_UNCONSTRAINED_MEMORY)
            options.add(so.CGC_NO_SYMBOLIC_RECEIVE_LENGTH)
            options.add(so.TRACK_MEMORY_MAPPING)
            options.add(so.AVOID_MULTIVALUED_READS)
            options.add(so.AVOID_MULTIVALUED_WRITES)

            # try to enable unicorn, continue if it doesn't exist
            options.add(so.UNICORN)
            l.info("unicorn tracing enabled")

            remove_options = so.simplification | { so.LAZY_SOLVES } | so.resilience | { so.SUPPORT_FLOATING_POINT }
            add_options = options
            entry_state = self.project.factory.entry_state(
                    add_options=add_options,
                    remove_options=remove_options)

            # map the CGC flag page
            fake_flag_data = entry_state.solver.BVV(FLAG_DATA)
            entry_state.memory.store(0x4347c000, fake_flag_data)
            # map the place where I put arguments
            entry_state.memory.map_region(0x2000, 0x10000, 7)

            entry_state.unicorn._register_check_count = 100
            entry_state.unicorn._runs_since_symbolic_data = 100