import ui
import time
import hardware
import math
import event

menu_stack = []
active_menu = None

class Menu():
    def __init__(self,name="menu",has_back=True):
        self.name=name
        self.items=[]
        self.__index = 0
        self.ui = ui.GroupRing(r=80)
        self.icon = ui.IconFlower(label=name,size=80)
        self.ui.element_center = self.icon
        
        self.angle = 0
        self.angle_step= 0.2
        if has_back:
            self.add(MenuItemBack())

    
    def __repr__(self):
        return "{} ({}): {}".format(self.name, self.__index, self.items)

    def add(self, item):
        self.items.append(item)
        self.ui.add(item.ui)
    
    def pop(self):
        self.items.pop()
        self.ui.children.pop()

    def start(self):
        print(self)
        active_menu = self
        render()

    def scroll(self, n=0):
        self.__index= (self.__index+n)%len(self.items)
        return self.items[self.__index]
    
    def rotate_by(self,angle):
        self.rotate_to(self.angle+angle)
    
    def rotate_to(self, angle):
        self.angle = angle%(math.pi*2)
        self.ui.angle_offset = self.angle
        self.icon.phi_offset = self.angle
    
    def rotate_steps(self, steps=1):
        self.rotate_by(self.angle_step*steps)
        
    def _get_hovered_index(self):
        index = round(-self.angle/(math.pi*2)*len(self.items))
        i = index%len(self.items)
        return i

    def get_hovered_item(self):
        return self.items[self._get_hovered_index()]
    
    def _get_angle_for_index(self,index):
        return (math.pi*2/len(self.items)*(index)+self.angle)%(math.pi*2)

    def _get_topness_for_index(self,index):
        angle = self._get_angle_for_index(index)
        dist = min(angle,math.pi*2-angle)
        topness = 1-(dist/math.pi)
        return topness

    

    def draw(self):
        
        hovered_index = self._get_hovered_index()
        for i in range(len(self.items)):
            item = self.items[i]
            my_extra = abs(self._get_topness_for_index(i))*40
            
            if i == hovered_index:
                item.ui.has_highlight=True
                my_extra+=20
            else:
                item.ui.has_highlight=False
            item.ui.size=30+my_extra
        self.ui.draw()
    

class MenuItem():
    def __init__(self,name="item",action=None):
        self.name= name
        self.action= action
        self.ui = ui.IconFlower(label=name)

    def __repr__(self):
        return "item: {} (action: {})".format(self.name,"?")

    def enter(self,data={}):
        print("Enter MenuItem {}".format(self.name))
        if self.action:
            self.action(data)

class MenuItemApp(MenuItem):
    def __init__(self,app):
        super().__init__(name=app.title)
        self.target = app
    
    def enter(self,data={}):
        if self.target:
            self.target.run()

class MenuItemSubmenu(MenuItem):
    def __init__(self,submenu):
        super().__init__(name=submenu.name)
        self.ui = submenu.icon
        self.target = submenu
    
    def enter(self,data={}):
        print("Enter Submenu {}".format(self.target.name))
        menu_stack.append(active_menu)
        set_active_menu(self.target)
        
class MenuItemBack(MenuItem):
    def __init__(self):
        super().__init__(name="<-")
    
    def enter(self,data={}):
        menu_back()

class MenuItemControl(MenuItem):
    def __init__(self,name,control):
        super().__init__(name=name)
        self.control=control
        self.ui=control.ui

    def enter(self):
        print("menu enter")
        self.control.enter()

    def scroll(self,delta):
        self.control.scroll(delta)

def on_scroll(d):
    if active_menu is None:
        return

    if d["index"]==0:#right button
        hovered=active_menu.get_hovered_item()
        if hasattr(hovered, "scroll"):
            hovered.scroll(d["value"])

    else: #index=1, #left button
        if active_menu.angle_step<0.5:
            active_menu.angle_step+=0.025
        if d["value"] == -1:
            active_menu.rotate_steps(-1)
        elif d["value"] == 1:
            active_menu.rotate_steps(1)

    render()

def on_scroll_captouch(d):
    if active_menu is None:
        return
    if abs(d["radius"]) < 10000:
        return
    print(d["angle"])
    active_menu.rotate_to(d["angle"]+math.pi)
    render()

def on_release(d):
    if active_menu is None:
        return

    active_menu.angle_step = 0.2
    render()
    
def on_enter(d):
    if active_menu is None:
        
        #TODO this should not bee needed...
        event.the_engine.userloop=None
        menu_back()
        return

    if active_menu:
        active_menu.get_hovered_item().enter()
        render()
    else:
        return

    
event.Event(name="menu rotation button",group_id="menu",
    condition=lambda e: e["type"] =="button" and not e["change"] and abs(e["value"])==1,
    action=on_scroll, enabled=True
)

event.Event(name="menu rotation captouch",group_id="menu",
    condition=lambda e: e["type"] =="captouch" and not e["change"] and abs(e["value"])==1 and e["index"]==2,
    action=on_scroll_captouch, enabled=False
)

event.Event(name="menu rotation button release",group_id="menu",
    condition=lambda e: e["type"] =="button" and e["change"] and e["value"] ==0,
    action=on_release, enabled=True
)

event.Event(name="menu button enter",group_id="menu",
    condition=lambda e: e["type"] =="button" and e["change"] and e["from"] == 2,
    action=on_enter, enabled=True
)

def render():
    print (active_menu)
    if active_menu is None:
        return
    
    ui.the_ctx.rectangle(-120,-120,240,240).rgb(0,0,0).fill()
    active_menu.draw()
    #hardware.display_update()

def set_active_menu(menu):
    global active_menu
    active_menu = menu

def menu_disable():
    global active_menu
    if active_menu:
        menu_stack.append(active_menu)
        active_menu=None

def menu_back():
    if not menu_stack:
        return

    previous = menu_stack.pop()

    set_active_menu(previous)
    render()