import gui
import gc

class ScreenManager:
    Screens = {"Empty":[[gui.DL_NOP()]]}
    Screen_key = "Empty"
    Current_Screen = Screens[Screen_key]
    last_screen = None

    def __init__(self):
        raise RuntimeError('Do Not create Instance of ScreenManager, use as singular class')

    @classmethod
    def Add_Screen(cls,screen, key, start = False):
        cls.Screens[key] = screen
        if start:
            cls.Screen_key = key
            cls.Current_Screen = cls.Screens[key]
            cls.Current_Screen.setup()
            cls.Current_Screen.draw()

    @classmethod
    def Set_Screen(cls,key, allow_garbage_collection=True):
        cls.Current_Screen.teardown()
        if allow_garbage_collection:
            gc.collect()
        cls.Current_Screen = cls.Screens[key]
        cls.Current_Screen.setup()
        cls.Current_Screen.draw()
        cls.last_screen = cls.Screen_key
        cls.Screen_key = key

    @classmethod
    def Switch_Screen_cb(cls, l):
        print(l)

    @classmethod
    def switch_to_last_screen(cls, l):
        cls.Set_Screen(cls.last_screen)




class Screen:

    def __init__(self):
        self.picture_buttons = None
        self.swipe_r = 50
        self.button_cbs_l = None
        self.button_icons_l = None
        self.press_sound_func = None
        self.press_sound = None


    def setup(self):
        self.gui_l_vsync_cb = [gui.EVT_VSYNC, self.vsync_cb]
        self.gui_l_swipe_cb = [gui.EVT_SWIPE, self.swipe_r, self.swipe_cb]
        self.gui_l_press_cb = [gui.EVT_PRESS, self.press_cb]
        self.gui_l_redraw_cb = [gui.EVT_REDRAW, self.redraw_cb]
        self.gui_list = [self.gui_l_vsync_cb, self.gui_l_swipe_cb, self.gui_l_redraw_cb, self.gui_l_press_cb]
        if (not self.picture_buttons is None):
            self.button_cbs_l, self.button_icons_l = self.create_picture_btns(self.picture_buttons)
            self.gui_list.extend(self.button_cbs_l)


    def vsync_cb(self, l):
        gui.redraw()

    def swipe_cb(self, l, start):
        if not start:
            swipe = gui.swipe_info()
            if swipe.dx >= self.swipe_r:
                self.previous_screen(None)
            if swipe.dx <= -self.swipe_r:
                self.next_screen(None)

    def press_cb(self, l):
        # if l[0] == 1:
        #     if l[1] == 255:
        #         from screenshot import screenshot_cb
        #         screenshot_cb(None)
        pass

    def redraw_cb(self, l):
        pass

    def draw(self):
        gui.show(self.gui_list)

    def teardown(self):
        pass

    def next_screen(self, gui_l):
        pass

    def previous_screen(self, gui_l):
        pass

    def new_data_cb(self):
        pass

    def wrap_callback(self, callback):
        def cb(*args, **kwargs):
            if self.press_sound_func and (self.press_sound is not None):
                self.press_sound_func(self.press_sound)
            callback(*args, **kwargs)
        return cb

    def create_picture_btns(self, picture_btns):
        button_cbs_l = []
        button_icons_l = [gui.DL_BEGIN(gui.PRIM_BITMAPS)]
        for i, button in enumerate(picture_btns):
            if button.get_callback() != None:
                button_cb_l = [
                    gui.PARAM_TAG_REGISTER,
                    self.wrap_callback(button.get_callback()),
                ]
                button_cb_l.append(button.name)
                button_cbs_l.append(button_cb_l)
                button.set_gui_l_index(len(button_icons_l))
            button_icons_l.extend(button.generate_gui_l(i + 1))
        button_icons_l.append(gui.DL_TAG(0))
        return button_cbs_l, button_icons_l

    def add_button_icons(self):
        if (not self.button_icons_l is None):
            self.gui_l_picture_btns_index = len(self.gui_list)
            self.gui_list.append(self.button_icons_l)








class LiveDisplayParameter:
    def __init__(self, init_val='', format='{}') -> None:
        self.format_string = format
        self.val = init_val
        self.display_val = [self.format_string.format(init_val)]

    def update(self, val=None):
        if val == None:
            val = self.val
        self.val = val
        self.display_val[0] = self.format_string.format(val)

    def set_format(self, format):
        self.format_string = format


class LiveDisplayValue:
    def __init__(self, init_val=0, format='{}', max=None, min=None, hysteresis = None, scale=1) -> None:
        self.format_string = format
        self.val = init_val
        self.display_val = [self.format_string.format(init_val*scale)]
        self.max = max if (max!=None) else (-min if (min!=None) else None)
        self.min = min if (min!=None) else (-max if (max!=None) else None)
        self.hysteresis = hysteresis
        self.scale = scale

    def update(self, val=None):
        if val == None:
            val = self.val
        self.val = val
        if self.hysteresis:
            self.display_val[0] = self.format_string.format(self.clamp(val*self.scale if val > self.hysteresis else 0))
        else:
            self.display_val[0] = self.format_string.format(self.clamp(val*self.scale))

    def set_format(self, format):
        self.format_string = format

    def clamp(self, val):
        if not (self.max or self.min):
            return val
        if val > self.max:
            return self.max
        elif val < self.min:
            return self.min
        else:
            return val

    def set_hysteresis(self, hysteresis):
        self.hysteresis = hysteresis

    def set_scale(self, scale):
        self.scale = scale