import os
import utime
import display
import light_sensor
import power
import buttons
import leds
import personal_state
import ujson
import urandom
import color

DAYCHANGE = [7,0]     #Time when day counter should change (default: 07:00 a.m.), because most nerds don't sleep at 0:00
mode = "DESTRUCTION"
PATH = "/apps/36c3_clock"
#For button mappings see line 73+

COLOR_BACKGROUND = [0,0,0]
COLOR_MAINTEXT = [208,208,206]
COLOR_DESTRUCTION = [254,80,0]
COLOR_HOPE = [0,187,49]

BATTERY_COLOR_GOOD = [0, 128, 0]
BATTERY_COLOR_OK = [128, 100, 0]
BATTERY_COLOR_BAD = [128, 0, 0]

DAY0 = utime.mktime((2019,12,26,DAYCHANGE[0],DAYCHANGE[1],0,0,0))

states = [
    ("No State", personal_state.NO_STATE),
    ("No Contact", personal_state.NO_CONTACT),
    ("Chaos", personal_state.CHAOS),
    ("Communication", personal_state.COMMUNICATION),
    ("Camp", personal_state.CAMP),
]

CRACKNAMES = []
for n in range(10):
    CRACKNAMES += [n]

DOTNAMES = []
for n in range(6):
    DOTNAMES += ["DOT_"+str(n)]

CRACKDOTS_TOP = []
for n in range(4):
    CRACKDOTS_TOP += ["CRACK_T"+str(n)]

CRACKDOTS_BOT = []
for n in range(4):
    CRACKDOTS_BOT += ["CRACK_B"+str(n)]

SWITCHTOTIMER = 0
if 'timer' in os.listdir('/apps'):
    if 'variables.json' in os.listdir('/apps/timer'):
        f = open('/apps/timer/variables.json', 'r')
        try:
            variables = ujson.loads(f.read())
            if "mode" and "runstamp" in variables:
                if variables["mode"] == 1:
                    SWITCHTOTIMER = variables["runstamp"]
        except:
            pass
        f.close()

alarm_hour = -1
alarm_minute = -1
if 'control_center' in os.listdir('/apps'):
    if 'cc_settings.txt' in os.listdir('/apps/control_center'):
        try:            
            with open('/apps/control_center/cc_settings.txt') as cc_settings:
                trash = int(cc_settings.read(4)) #I don't need the firs 4 chars
                if int(cc_settings.read(1)) != 0:
                    alarm_hour = int(cc_settings.read(2))
                    alarm_minute = int(cc_settings.read(2))
        except:
            pass

pressed_prev = 0
button_sel_time = 0
button_up_time = 0
button_down_time = 0
flashlight_led = 0
flashlight_bar = 0

def check_buttons():
    global pressed_prev, button_sel_time, button_up_time, button_down_time, flashlight_led, flashlight_bar, mode, SWITCHTOTIMER

    t = utime.time_ms()
    pressed = buttons.read(buttons.BOTTOM_LEFT | buttons.TOP_RIGHT | buttons.BOTTOM_RIGHT)

    if pressed & buttons.TOP_RIGHT and not pressed_prev & buttons.TOP_RIGHT:
        button_sel_time = t
    elif not pressed & buttons.TOP_RIGHT and pressed_prev & buttons.TOP_RIGHT:
        if button_sel_time+250 < t:                 #LONG PRESSED SET
            os.exec("apps/timer/__init__.py")           #switch app to timer
        else:                                       #SHORT PRESS SET
            if mode != "DESTRUCTION":                   #switch clock design
                mode = "DESTRUCTION"
            else:
                mode = "HOPE"

    if pressed & buttons.BOTTOM_RIGHT and not pressed_prev & buttons.BOTTOM_RIGHT:
        button_up_time = t
    elif not pressed & buttons.BOTTOM_RIGHT and pressed_prev & buttons.BOTTOM_RIGHT:
        if button_up_time+250 < t:                  #LONG PRESSED UP
            flashlight_bar+=4                           #change flashlight bar brightness
            if flashlight_bar > 8:
                flashlight_bar = 0
            leds.dim_top(flashlight_bar)
            for led in range(0,11):
                leds.set(led, [255,255,255])
        else:                                       #SHORT PRESSED UP
            flashlight_bar=0                            #deactivate flashlight bar and toggle flashlight led
            leds.dim_top(0)
            if flashlight_led == 0:
                leds.set_flashlight(1)
                flashlight_led = 1
            else:
                leds.set_flashlight(0)
                flashlight_led = 0

    if pressed & buttons.BOTTOM_LEFT and not pressed_prev & buttons.BOTTOM_LEFT:
        button_down_time = t
    elif not pressed & buttons.BOTTOM_LEFT and pressed_prev & buttons.BOTTOM_LEFT:
        if button_down_time+250 < t:                #LONG PRESSED DOWN
            os.exec("apps/ecg/__init__.py")             #switch app to ecg
        else:                                       #SHORT PRESSED DOWN
            numstates = len(states)                     #switch personal state
            current, _ = personal_state.get()
            current = (current + 1) % numstates
            state = states[current]
            personal_state.set(state[1], True)

    pressed_prev = pressed
    if SWITCHTOTIMER > 0 and SWITCHTOTIMER <= utime.time_ms()+3000:
        os.exec("apps/timer/__init__.py")


def get_bat_color(v):
    if v > 3.8:
        return BATTERY_COLOR_GOOD
    if v > 3.6:
        return BATTERY_COLOR_OK
    return BATTERY_COLOR_BAD


def render_battery(display, pos_x=142, pos_y=72):
    v = os.read_battery()
    c = get_bat_color(v)

    if not c:
        return
    display.rect(pos_x, pos_y, pos_x + 15, pos_y + 7, filled=True, col=c)
    display.rect(pos_x + 15, pos_y + 2, pos_x + 17, pos_y + 5, filled=True, col=c)
    if v < 4.0:
        display.rect(pos_x + 11, pos_y + 1, pos_x + 14, pos_y + 6, filled=True, col=[0, 0, 0])
    if v < 3.8:
        display.rect(pos_x + 6, pos_y + 1, pos_x + 11, pos_y + 6, filled=True, col=[0, 0, 0])
    if v < 3.6:
        display.rect(pos_x + 1, pos_y + 1, pos_x + 6, pos_y + 6, filled=True, col=[0, 0, 0])
    render_charging(display, pos_x + 6, pos_y)


def render_charging(display, pos_x, pos_y):
    v_in = power.read_chargein_voltage()
    if v_in > 4.0:
        c = [0, 0, 0]
        c_shade = [120, 120, 120]
        display.pixel(pos_x + 1, pos_y, col=c)
        display.pixel(pos_x + 1, pos_y, col=c)
        display.pixel(pos_x + 2, pos_y, col=c_shade)
        display.pixel(pos_x + 1, pos_y + 1, col=c)
        display.pixel(pos_x, pos_y + 1, col=c_shade)
        display.pixel(pos_x + 1, pos_y + 2, col=c)
        display.pixel(pos_x, pos_y + 2, col=c)
        display.pixel(pos_x, pos_y + 3, col=c)
        display.pixel(pos_x + 1, pos_y + 3, col=c)
        display.pixel(pos_x + 2, pos_y + 3, col=c)
        display.pixel(pos_x + 3, pos_y + 3, col=c_shade)
        display.pixel(pos_x + 2, pos_y + 4, col=c)
        display.pixel(pos_x + 3, pos_y + 4, col=c)
        display.pixel(pos_x + 4, pos_y + 4, col=c)
        display.pixel(pos_x + 1, pos_y + 4, col=c_shade)
        display.pixel(pos_x + 3, pos_y + 5, col=c)
        display.pixel(pos_x + 4, pos_y + 5, col=c)
        display.pixel(pos_x + 3, pos_y + 6, col=c)
        display.pixel(pos_x + 4, pos_y + 6, col=c_shade)
        display.pixel(pos_x + 3, pos_y + 7, col=c)
        display.pixel(pos_x + 2, pos_y + 7, col=c_shade)

def render_char_new(display, char, start_x, start_y, digitcolor, mode="DESTRUCTION", cracks=[]):
    char_data = open(PATH+'/'+char+'.txt', 'r')
    line_data = char_data.readlines()
    char_data.close()
    cracks_in = []
    cracks_out = []
    cracks_anker = []
    leafs = []
    for i in cracks:
        cracks_in += [chr(0x41+i)]
        cracks_out += [chr(0x61+i)]
        cracks_anker += [chr(0x30+i)]
    for y in range(len(line_data)):
        for x in range(len(line_data[y])):
            if (line_data[y][x] in cracks_in) or (line_data[y][x] in cracks_out):
                if mode == "HOPE":
                    display.pixel(start_x+x, start_y+y, col=COLOR_HOPE)
            elif line_data[y][x] in cracks_anker:
                if len(line_data[y]) > 30:
                    leafs += [[start_x+x, start_y+y, x>18]]
                else:
                    leafs += [[start_x+x, start_y+y, x>8]]
            elif line_data[y][x] in ['*','A','B','C','D','E','F','G','H','I','J']:
                display.pixel(start_x+x, start_y+y, col=digitcolor)
        check_buttons()
#        display.update()
    return leafs

def render_leafs(display, leafs):
    for leaf in leafs:
        dir = 1-(leaf[2]*2)
        display.pixel(leaf[0]-0*dir, leaf[1]-0, col=COLOR_HOPE)
        display.pixel(leaf[0]-1*dir, leaf[1]-1, col=COLOR_HOPE)
        display.pixel(leaf[0]-2*dir, leaf[1]-2, col=COLOR_HOPE)
        display.pixel(leaf[0]-3*dir, leaf[1]-3, col=COLOR_HOPE)
        display.pixel(leaf[0]-4*dir, leaf[1]-3, col=COLOR_HOPE)
        display.pixel(leaf[0]-5*dir, leaf[1]-3, col=COLOR_HOPE)
        display.pixel(leaf[0]-6*dir, leaf[1]-3, col=COLOR_HOPE)
        display.pixel(leaf[0]-6*dir, leaf[1]-4, col=COLOR_HOPE)
        display.pixel(leaf[0]-7*dir, leaf[1]-3, col=COLOR_HOPE)
        display.pixel(leaf[0]-6*dir, leaf[1]-2, col=COLOR_HOPE)
        display.pixel(leaf[0]-0*dir, leaf[1]-1, col=COLOR_HOPE)
        display.pixel(leaf[0]-0*dir, leaf[1]-2, col=COLOR_HOPE)
        display.pixel(leaf[0]-0*dir, leaf[1]-3, col=COLOR_HOPE)
        display.pixel(leaf[0]-1*dir, leaf[1]-4, col=COLOR_HOPE)
        display.pixel(leaf[0]-2*dir, leaf[1]-5, col=COLOR_HOPE)
        display.pixel(leaf[0]-3*dir, leaf[1]-6, col=COLOR_HOPE)
        display.pixel(leaf[0]-4*dir, leaf[1]-6, col=COLOR_HOPE)
        display.pixel(leaf[0]-5*dir, leaf[1]-6, col=COLOR_HOPE)
        display.pixel(leaf[0]-6*dir, leaf[1]-6, col=COLOR_HOPE)
        display.pixel(leaf[0]-7*dir, leaf[1]-6, col=COLOR_HOPE)
        display.pixel(leaf[0]-8*dir, leaf[1]-6, col=COLOR_HOPE)
        display.pixel(leaf[0]-9*dir, leaf[1]-6, col=COLOR_HOPE)
        display.pixel(leaf[0]-10*dir, leaf[1]-6, col=COLOR_HOPE)
        display.pixel(leaf[0]-11*dir, leaf[1]-6, col=COLOR_HOPE)
        display.pixel(leaf[0]-12*dir, leaf[1]-6, col=COLOR_HOPE)
        display.pixel(leaf[0]-13*dir, leaf[1]-6, col=COLOR_HOPE)
        display.pixel(leaf[0]-12*dir, leaf[1]-5, col=COLOR_HOPE)
        display.pixel(leaf[0]-11*dir, leaf[1]-4, col=COLOR_HOPE)
        display.pixel(leaf[0]-10*dir, leaf[1]-3, col=COLOR_HOPE)
        display.pixel(leaf[0]-9*dir, leaf[1]-2, col=COLOR_HOPE)
        display.pixel(leaf[0]-8*dir, leaf[1]-1, col=COLOR_HOPE)
        display.pixel(leaf[0]-7*dir, leaf[1]-0, col=COLOR_HOPE)
        display.pixel(leaf[0]-6*dir, leaf[1]-0, col=COLOR_HOPE)
        display.pixel(leaf[0]-5*dir, leaf[1]-0, col=COLOR_HOPE)
        display.pixel(leaf[0]-4*dir, leaf[1]-0, col=COLOR_HOPE)
        display.pixel(leaf[0]-4*dir, leaf[1]-1, col=COLOR_HOPE)
        display.pixel(leaf[0]-3*dir, leaf[1]-0, col=COLOR_HOPE)
        display.pixel(leaf[0]-4*dir, leaf[1]+1, col=COLOR_HOPE)

def render_caption(display, pos_x, pos_y, caption, captioncolor = COLOR_DESTRUCTION, y_shift = 0):
    y = 0.5
    display.line(pos_x-7-(len(caption)-1)*8,int(pos_y-6+y_shift*(len(caption)-1)+y),156,pos_y-6, col = captioncolor)
    display.line(pos_x-7-(len(caption)-1)*8,int(pos_y-5+y_shift*(len(caption)-1)+y),156,pos_y-5, col = captioncolor)
    display.line(pos_x-7-(len(caption)-1)*8,int(pos_y+6+y_shift*(len(caption)-1)+y),156,pos_y+6, col = captioncolor)
    display.line(pos_x-7-(len(caption)-1)*8,int(pos_y+7+y_shift*(len(caption)-1)+y),156,pos_y+7, col = captioncolor)
    for n in range(len(caption)):
        display.rect(pos_x-7-n*8,int(pos_y-5+y),pos_x-n*8,int(pos_y+6+y), col = captioncolor, filled=False, size=1)
        render_char_new(display, "LITTLE_"+caption[-(n+1):][0], pos_x-6-n*8,int(pos_y-4+y), captioncolor)
        y += y_shift


def shuffle(list):
    listlen = len(list)
    for a in range(listlen):
        b = urandom.randrange(listlen)
        list[a], list[b] = list[b], list[a]

def render_clock(display, mode):
    time=utime.time()+3   #render will take about 3 seconds, so an offset is added
    shuffle(CRACKNAMES)
    cracks = 0
    print_cracks = [[],[],[],[],[]]
    for n in range(5):
        for i in range(urandom.randrange(1,3)):
            print_cracks[n] += [CRACKNAMES[cracks]]
            cracks += 1
    shuffle(print_cracks)

    year, month, mday, hour, min, sec, wday, yday = utime.localtime(time)
    caption = "DAY "+str((time-DAY0)//(3600*24))

    display.clear()
    if hour == alarm_hour and min == alarm_minute:
        display.print(" Switching ", posx=3, posy=10, fg=color.WHITE)
        display.print("to Control ", posx=3, posy=30, fg=color.WHITE)
        display.print("Center app.", posx=3, posy=50, fg=color.WHITE)
        display.update()
        display.backlight(23)
        os.exec("apps/control_center/__init__.py")
    leafs=[]
    leafs+=render_char_new(display, "BIG_"+str(hour//10), 0,5, COLOR_MAINTEXT, mode, print_cracks[0])
    leafs+=render_char_new(display, "BIG_"+str(hour%10), 36,5, COLOR_MAINTEXT, mode, print_cracks[1])
    leafs+=render_char_new(display, "DOTS_"+str(urandom.randrange(6)), 72,39, COLOR_MAINTEXT, mode, print_cracks[2])
    leafs+=render_char_new(display, "BIG_"+str(min//10), 85,5, COLOR_MAINTEXT, mode, print_cracks[3])
    leafs+=render_char_new(display, "BIG_"+str(min%10), 121,5, COLOR_MAINTEXT, mode, print_cracks[4])
    if mode != "HOPE":
        captioncolor = COLOR_DESTRUCTION
    else:
        captioncolor = COLOR_HOPE
        render_leafs(display,leafs)

    y_shift = urandom.random() + 1/len(caption)

    y = 0.5
    if urandom.randrange(2) == 1:
        y_shift = y_shift*-1
    render_caption(display, 156, 57, caption, captioncolor, y_shift)

oldmode = ""
oldbar = -1
top = 10
bot = 10
rendered = False

x = os.urandom(1)[0]
for i in range(32):
    x+=os.urandom(1)[0]
urandom.seed(x)
with display.open() as display:
    while True:
        if mode != oldmode:
            oldmode = mode
            rendered = False
            display.clear(COLOR_MAINTEXT)
            if mode != "HOPE":
                display.print("Loading", posx=31, posy=10, fg=COLOR_DESTRUCTION)
                display.print("destruction", posx=3, posy=30, fg=COLOR_DESTRUCTION)
                display.print("clock ...", posx=17, posy=50, fg=COLOR_DESTRUCTION)
            else:
                display.print("Loading", posx=31, posy=10, fg=COLOR_HOPE)
                display.print("hope", posx=52, posy=30, fg=COLOR_HOPE)
                display.print("clock ...", posx=17, posy=50, fg=COLOR_HOPE)
            display.update()
            render_clock(display, mode)
            display.rect(0, 72, int(139*(utime.time_ms()%60000)/57000), 80, col=COLOR_MAINTEXT)
            display.update()

        check_buttons()

        bar = int(139*(utime.time_ms()%60000)/57000)
        if bar != oldbar:
            oldbar = bar
            if bar <= 139:
                if mode == "HOPE":
                    display.line(bar, 72, bar, 80, col=COLOR_HOPE)
                top += urandom.random()*4-2
                bot += urandom.random()*4-2
                if top < 8:
                    top += (8-top)*(8-top)/32
                if top > 12:
                    top = 12
                if top < 0:
                    top = 0
                if bot < 8:
                    bot += (8-bot)*(8-bot)/32
                if bot > 12:
                    bot = 12
                if bot < 0:
                    bot = 0
                if (bot + top) < 2:
                    top += 0.5
                    bot += 0.5
                cuttop = 79 - top
                cutbot = 73 + bot
                if cuttop < 72:
                    cuttop = 72
                if cutbot > 80:
                    cutbot = 80
                display.line(bar, int(cuttop), bar, int(cutbot), col=COLOR_MAINTEXT)
                render_battery(display)
                display.update()
                rendered = False

            elif rendered == False:
                render_clock(display, mode)
                rendered = True