import json
import logging
import subprocess
import time

from input_event import EventLog
from input_policy import UtgBasedInputPolicy, UtgDfsPolicy

POLICY_NONE = "none"
POLICY_MONKEY = "monkey"
POLICY_DFS = "dfs"
POLICY_MANUAL = "manual"

DEFAULT_POLICY = POLICY_DFS
DEFAULT_EVENT_INTERVAL = 1
DEFAULT_EVENT_COUNT = 1000
DEFAULT_TIMEOUT = -1


class UnknownInputException(Exception):
    pass


class InputManager(object):
    """
    This class manages all events to send during app running
    """

    def __init__(self, device, app, policy_name, random_input,
                 event_count, event_interval,
                 script_path=None, profiling_method=None):
        """
        manage input event sent to the target device
        :param device: instance of Device
        :param app: instance of App
        :param policy_name: policy of generating events, string
        :return:
        """
        self.logger = logging.getLogger('InputEventManager')
        self.enabled = True

        self.device = device
        self.app = app
        self.policy_name = policy_name
        self.random_input = random_input
        self.events = []
        self.policy = None
        self.script = None
        self.event_count = event_count
        self.event_interval = event_interval

        self.monkey = None

        if script_path is not None:
            f = open(script_path, 'r')
            script_dict = json.load(f)
            from input_script import DroidBotScript
            self.script = DroidBotScript(script_dict)

        self.policy = self.get_input_policy(device, app)
        self.profiling_method = profiling_method

    def get_input_policy(self, device, app):
        input_policy = None
        if self.policy_name == POLICY_NONE:
            input_policy = None
        elif self.policy_name == POLICY_MONKEY:
            input_policy = None
        elif self.policy_name == POLICY_DFS:
            input_policy = UtgDfsPolicy(device, app, self.random_input)
        # elif self.policy_name == POLICY_MANUAL:
        #     input_policy = ManualEventFactory(device, app)
        else:
            input_policy = None
        if isinstance(input_policy, UtgBasedInputPolicy):
            input_policy.script = self.script
        return input_policy

    def add_event(self, event):
        """
        add one event to the event list
        :param event: the event to be added, should be subclass of AppEvent
        :return:
        """
        if event is None:
            return
        self.events.append(event)

        event_log = EventLog(self.device, self.app, event, self.profiling_method)
        event_log.start()
        while True:
            time.sleep(self.event_interval)
            if not self.device.pause_sending_event:
                break
        event_log.stop()

    def start(self):
        """
        start sending event
        """
        self.logger.info("start sending events, policy is %s" % self.policy_name)

        try:
            if self.policy is not None:
                self.policy.start(self)
            elif self.policy_name == POLICY_NONE:
                self.device.start_app(self.app)
                if self.event_count == 0:
                    return
                while self.enabled:
                    time.sleep(1)
            elif self.policy_name == POLICY_MONKEY:
                throttle = self.event_interval * 1000
                monkey_cmd = "adb -s %s shell monkey %s --ignore-crashes --ignore-security-exceptions" \
                             " --throttle %d %d" % \
                             (self.device.serial,
                              "" if self.app.get_package_name() is None else "-p " + self.app.get_package_name(),
                              throttle,
                              self.event_count)
                self.monkey = subprocess.Popen(monkey_cmd.split(),
                                               stdout=subprocess.PIPE,
                                               stderr=subprocess.PIPE)
                while self.enabled:
                    time.sleep(1)
            elif self.policy_name == POLICY_MANUAL:
                self.device.start_app(self.app)
                while self.enabled:
                    keyboard_input = raw_input("press ENTER to save current state, type q to exit...")
                    if keyboard_input.startswith('q'):
                        break
                    state = self.device.get_current_state()
                    if state is not None:
                        state.save2dir()
        except KeyboardInterrupt:
            pass

        self.stop()
        self.logger.info("Finish sending events")

    def stop(self):
        """
        stop sending event
        """
        if self.monkey:
            self.monkey.terminate()
            self.monkey = None
            pid = self.device.get_app_pid("com.android.commands.monkey")
            if pid is not None:
                self.device.adb.shell("kill -9 %d" % pid)
        self.enabled = False

        # BEGIN - For debugging. @Minyi
        if isinstance(self.policy, UtgBasedInputPolicy):
            msg = "%s: %d/%d\n" % (self.app.package_name, len(self.policy.explored_activities), len(self.policy.all_activities))
            with open("/home/chimps/temp/coverage.txt", "a") as myfile:
                myfile.write(msg)
            print msg
        # END

@@ -5049,373 +5049,4 @@
 lse%0A
-%0A        # BEGIN - For debugging. @Minyi%0A        if isinstance(self.policy, UtgBasedInputPolicy):%0A            msg = %22%25s: %25d/%25d%5Cn%22 %25 (self.app.package_name, len(self.policy.explored_activities), len(self.policy.all_activities))%0A            with open(%22/home/chimps/temp/coverage.txt%22, %22a%22) as myfile:%0A                myfile.write(msg)%0A            print msg%0A        # END%0A

remove debug lines