import MelAPI.ssbm as ssbm
from MelAPI.state import *
import MelAPI.state_manager as state_manager
import MelAPI.memory_watcher as memory_watcher
from MelAPI.menu_manager import *
from MelAPI.pad import *

import threading
import time
import os
import MelAPI.util as util


class CPU(threading.Thread):
    def __init__(self, character='falcon', port=1):
        threading.Thread.__init__(self)

        self.c = character

        self.first_frame = True
        self.action_counter = 0
        self.spam_toggle = False
        self.release_toggle = False

        self.dolphin_conf = 'MelAPI/dolphin_conf'

        self.state = ssbm.GameMemory()
        self.sm = state_manager.StateManager([0, 1])  # Player ports to watch
        self.write_locations()

        # Player ids
        self.pid = port
        self.pids = [self.pid]

        self.menu_manager = MenuManager(characters[self.c], pid=self.pid)

        print('Creating MemoryWatcher.')
        mwType = memory_watcher.MemoryWatcher
        if self.zmq:
          mwType = memory_watcher.MemoryWatcherZMQ
        self.mw = mwType(self.dolphin_conf + '/MemoryWatcher/MemoryWatcher')

        pipe_dir = self.dolphin_conf + '/Pipes/'
        print('Creating Pads at %s. Open dolphin now.' % pipe_dir)
        util.makedirs(pipe_dir)

        paths = [pipe_dir + "p%d" % self.pid]
        self.get_pads = util.async_map(Pad, paths)
        self.init_stats()

    def _run(self, frames=None, dolphin_process=None):
        try:
            self.pads = self.get_pads()
        except KeyboardInterrupt:
            print("Pipes not initialized!")
            return

        for pid, pad in zip(self.pids, self.pads):
            self.menu_manager.pad = pad

        self.settings_mm = MenuManager(settings, pid=self.pids[0], pad=self.pads[0])

        print('Starting run loop.')
        self.start_time = time.time()

        try:
            while True:
                self.advance_frame()
        except KeyboardInterrupt:
            self.print_stats()

    def init_stats(self):
        self.total_frames = 0
        self.skip_frames = 0
        self.thinking_time = 0

    def print_stats(self):
        total_time = time.time() - self.start_time
        frac_skipped = self.skip_frames / self.total_frames
        frac_thinking = self.thinking_time * 1000 / self.total_frames
        print('Total Time:', total_time)
        print('Total Frames:', self.total_frames)
        print('Average FPS:', self.total_frames / total_time)
        print('Fraction Skipped: {:.6f}'.format(frac_skipped))
        print('Average Thinking Time (ms): {:.6f}'.format(frac_thinking))

    def write_locations(self):
        path = self.dolphin_conf + '/MemoryWatcher/'
        util.makedirs(path)
        print('Writing locations to:', path)
        with open(path + 'Locations.txt', 'w') as f:
            f.write('\n'.join(self.sm.locations()))

    def advance_frame(self):
        last_frame = self.state.frame

        self.update_state()
        if self.state.frame > last_frame:
            skipped_frames = self.state.frame - last_frame - 1
            if skipped_frames > 0:
                self.skip_frames += skipped_frames
                print("Skipped frames ", skipped_frames)
            self.total_frames += self.state.frame - last_frame
            last_frame = self.state.frame

            start = time.time()
            self.make_action()
            self.thinking_time += time.time() - start

            #if self.state.frame % (15 * 60) == 0:
                #self.print_stats()

        self.mw.advance()

    def update_state(self):
        messages = self.mw.get_messages()
        for message in messages:
            # print(message)
            self.sm.handle(self.state, *message)

    def spam(self, button):
        if self.spam_toggle:
            self.pads[0].press_button(button)
            self.spam_toggle = False
        else:
            self.pads[0].release_button(button)
            self.spam_toggle = True

    def make_action(self):
        # print(self.state.players[1])
        if self.state.menu == Menu.Characters.value or self.state.menu == Menu.Stages.value:
            self.spam(Button.START)
            #if not self.menu_manager.reached:
            #    self.menu_manager.move(self.state)

        elif self.state.menu == Menu.PostGame.value:
            if not self.release_toggle:
                self.pads[0].release_all()
                self.release_toggle = True
            self.spam(Button.START)

        elif self.state.menu == Menu.Game.value:
            self.release_toggle = False
            self.play()

    def play(self):
        pass
            