import time
import urequests
import ugfx
import wifi
import machine #to get the reset cause
import badge #to set splashscreen and wait for eink display
import deepsleep #deepsleep in the main routine
import appglue #to return home
import dialogs #to query the user for the url

#################################
## Helper functions and config ##
#################################

#don't show refesh message when successfull, to save refreshs/energy
SHOW_WIFI_MESSAGES = False
BATTERYBAR_HEIGHT = 4 #set 0 tol disable batterybar

MENUTEXT = """[A] Set URL
[B] Return to home
[Start] start display routine
[Select] Select font
Font: """
OWNNAME = "infoscreen"
SLEEPTIME = 8*60*60 #somehow doesn't work?

#due to the weird callback-structure, setters must return to the main screen on their own
def get_font():
  return badge.nvs_get_str(OWNNAME,"font","DejaVuSans20")
  
def set_font(font):
  badge.nvs_set_str(OWNNAME,"font",font)
  mainmenu()

def get_url():
  return badge.nvs_get_str(OWNNAME,"url","http://voidman.at/cal/cal.php?name=oeh_public")
  
def set_url(url):
  badge.nvs_set_str(OWNNAME,"url",url)
  mainmenu()

def wait_wifi(): #part of every 2nd app, display "still connecting to wifi anyways"
  if(SHOW_WIFI_MESSAGES):
    ugfx.clear(ugfx.BLACK)
    ugfx.flush()
    ugfx.string(50, 25, "STILL", "Roboto_BlackItalic24", ugfx.WHITE)
    ugfx.string(30, 50, "Connecting to wifi", "PermanentMarker22", ugfx.WHITE)
    le = ugfx.get_string_width("Connecting to wifi", "PermanentMarker22")
    ugfx.line(30, 72, 30 + 14 + le, 72, ugfx.WHITE)
    ugfx.string(140, 75, "Anyway", "Roboto_BlackItalic24", ugfx.WHITE)
    ugfx.flush()

  #slower than default to save energy
  while not wifi.sta_if.isconnected():
    time.sleep(0.5)
    
def show(newtext): #display as much of \n separated text in the default font as possible
  font = get_font()
  fontheight = int(font[-2:]) #the last 2 digits of a font name give its height
  lines = int(ugfx.height()/fontheight) #the number of lines is floor(displayheight/fontheight)
  firstN = newtext.split("\n")[:lines]
  ugfx.clear(ugfx.WHITE)
  ugfx.flush()
  i=0 #line counter
  for line in firstN:
    ypos = 1 + i * fontheight #ypos 0 is invalid somehow?
    ugfx.string(1,ypos,line, get_font(), ugfx.BLACK)
    i+=1
  
  # code to draw batterybar, see https://github.com/SHA2017-badge/micropython-esp32/blob/master/esp32/modules/splash.py and easydraw.py
  if(BATTERYBAR_HEIGHT > 0):
    vMin = badge.nvs_get_u16('batt', 'vmin', 3500) # mV
    vMax = badge.nvs_get_u16('batt', 'vmax', 4100) # mV
    vBatt = badge.battery_volt_sense()
    vDiff = vMax-vMin
    battPercent = (vBatt-vMin)/vDiff
    battPercent = min(1.0, max(0.0, battPercent)) #sanitize between 1.0 and 0.0  
    battBarSize = int(battPercent*(ugfx.width()-2))
    battBarYPos = int(ugfx.height()-BATTERYBAR_HEIGHT-1)
    ugfx.area(1,battBarYPos,battBarSize,BATTERYBAR_HEIGHT,ugfx.BLACK) #draw a battery bar at the bottom of the screen
  ugfx.flush()
  
def set_font_menu(): #menu 
  options = ugfx.List(0,0,int(ugfx.width()),ugfx.height())
  #options already handles up/down on it's own
  for font in ugfx.fonts_list(): #all available system fonts
    options.add_item(font)

  ugfx.input_init()
  ugfx.input_attach(ugfx.JOY_UP, lambda pushed: ugfx.flush() if pushed else False)
  ugfx.input_attach(ugfx.JOY_DOWN, lambda pushed: ugfx.flush() if pushed else False)
  ugfx.input_attach(ugfx.BTN_START,lambda pushed: set_font(options.selected_text()) if pushed else False)
  ugfx.input_attach(ugfx.BTN_A,lambda pushed: set_font(options.selected_text()) if pushed else False)
  ugfx.input_attach(ugfx.BTN_B,lambda pushed: mainmenu() if pushed else False)
  ugfx.flush()

##########################
## Actual program logic ##
##########################

def mainroutine():
  wifi.init()
  wait_wifi()
  try:
    if(SHOW_WIFI_MESSAGES):
      show("Requesting...")
    r = urequests.get(get_url())
  except:
    show("Connection problems")
    if not wifi.sta_if.isconnected():
      wifi.init()
      wait_wifi()
  else:
    if r.status_code == 200:
      show(r.text)
      r.close()
    else:
      show("Error at fetching file")
      r.close()
      
    badge.nvs_set_str("boot","splash", OWNNAME) #set badge to reboot into this
    badge.nvs_set_str(OWNNAME, "sleepuntil", str(time.time() + SLEEPTIME))
    badge.eink_busy_wait() #wait for eink display to draw
    deepsleep.start_sleeping(SLEEPTIME*1000) #let's go to sleep
  
def mainmenu():
  url = get_url()
  show(MENUTEXT+get_font()+"\n"+url)
  ugfx.input_init()
  ugfx.input_attach(ugfx.BTN_A,lambda pushed: dialogs.prompt_text("Enter URL", url, cb=set_url))
  ugfx.input_attach(ugfx.BTN_B,lambda pressed: appglue.start_app("launcher"))
  ugfx.input_attach(ugfx.BTN_START,lambda pressed: mainroutine())
  ugfx.input_attach(ugfx.BTN_SELECT,lambda pressed: set_font_menu())

##################
## Startup code ##
##################

ugfx.init()
badge.init()

displayloop = badge.nvs_get_str('boot','splash', "splash") == OWNNAME #check if the app is inside the deepsleep-mode that full-resets all memory
if( machine.reset_cause() == machine.DEEPSLEEP_RESET and displayloop ):
  if(time.time() < int(badge.nvs_get_str(OWNNAME, "sleepuntil", "0")) #if we wake up earlier but from timer (due to RTC-bug) sleep again
     and (time.time() * int(badge.nvs_get_str(OWNNAME, "sleepuntil", "0")) > 0) ): #also if the sleepuntil overflows to negative (or the time.time we wake up
    deepsleep.start_sleeping(SLEEPTIME*1000) #let's go to sleep
  mainroutine()
else: #when the app reset with the reset-button on the back or started normally
  badge.nvs_set_str("boot","splash","splash") #reset it to boot to splash
  mainmenu()