import sndmixer, binascii, system, time, wifi, audio, machine, display, keypad, touchpads
from umqtt.simple import MQTTClient

rate = 20

SERVER_IP = "clamans.mobach.nl"

sndmixer.begin(16)
synth = sndmixer.synth()
sndmixer.volume(synth, 0)
sndmixer.waveform(synth, 0)
sndmixer.freq(synth, 1080)
sndmixer.play(synth)

myvolume = 32

toplay = []

players = {}

start = 0
end = 0
lastpreslen = 0
message = ''

alfabet = {
    'A':'.-', 'B':'-...', 'C':'-.-.', 'D':'-..', 'E':'.', 'F':'..-.', 'G':'--.',
    'H':'....', 'I':'..', 'J':'.---', 'K':'-.-', 'L':'.-..', 'M':'--', 'N':'-.',
    'O':'---', 'P':'.--.', 'Q':'--.-', 'R':'.-.', 'S':'...', 'T':'-', 'U':'..-',
    'V':'...-', 'W':'.--', 'X':'-..-', 'Y':'-.--', 'Z':'--..', '0':'-----',
    '1':'.----', '2':'..---', '3':'...--', '4':'....-', '5':'.....', '6':'-....',
    '7':'--...', '8':'---..', '9':'----', '.':'-.-.-', ',':'--..--', '?':'..--..',
    '!':'-.-.--', '-':'-....-', '/':'-..-.', ':':'---...', "'":'.----.',
    ')':'-.--.-', ';':'-.-.-', '(':'-.--.', '=':'-...-', '@':'.--.-.', '&':'.–...'}

def lookupalfabet(letterding):
    global alfabet
    for teken in alfabet:
        if alfabet[teken] == letterding:
            return teken

def player(mytimer):
    global toplay
    if toplay:
        sndmixer.volume(synth, myvolume if toplay.pop(0) else 0)
    else:
        c.check_msg()

def blink(mytimer):
    global end,message,letterding,c
    if mytimer.events()[0] % rate == 0:
        if (mytimer.events()[0] / rate)  % 2 == 0:
            display.drawPixel(0, 0, 0xFFFFFF)
            display.flush()
        else:
            display.drawPixel(0, 0, 0x000000)
            display.flush()
    if end:
        if time.ticks_diff(time.ticks_us(), end) > 2000000:
            end = 0
            #print("Sending message", message)
            c.publish('/morse/message', message)
            message = ''

def on_key(key_index, pressed):
    global start, end, letterding, message, lastpreslen
    x, y = key_index % 4, int(key_index / 4)
    if (x, y) == (3, 3):
        if pressed:
            sndmixer.volume(synth, myvolume)
            if end:
                tijd = time.ticks_diff(time.ticks_us(), start)
                message += "0" * int(round(tijd / 25000))
            start = time.ticks_us()
        else:
            sndmixer.volume(synth, 0)
            tijd = time.ticks_diff(time.ticks_us(), start)
            message += "1" * int(round(tijd / 25000))
            end = time.ticks_us()

def playletter(letters):
    global toplay
    for letter in letters:
        if letter == ' ':
            toplay += [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,]
        elif letter in alfabet:
            for dotdash in alfabet[letter]:
                if dotdash == '.':
                    toplay += [1, 1, 1, 0, 0, 0]
                elif dotdash == '-':
                    toplay += [1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0]
            toplay += [0, 0, 0, 0]

def playmessage(msg):
    for letter in msg:
        playletter(letter)

def startupwifi():
    # Connect to Wi-Fi
    if not wifi.status():
        audio.play('/cache/system/wifi_connecting.mp3')
        wifi.connect()
        wifi.wait()
        if not wifi.status():
            audio.play('/cache/system/wifi_failed.mp3')
            time.sleep(6)
            system.launcher()

def cancelmsg(pressed):
    global toplay
    if pressed:
        toplay = []

def vol_up(pressed):
    global myvolume
    if pressed:
        myvolume += 32
        if myvolume > 255:
            myvolume = 255

def vol_down(pressed):
    global myvolume
    if pressed:
        myvolume -= 32
        if myvolume < 0:
            myvolume = 0

def sub_cb(topic, msg):
    global players, rate, toplay
    topic = topic.decode('utf-8')
    msg = msg.decode('utf-8')
    print((topic, msg))
    if topic.endswith("/available"):
        mplayer = topic.split("/")[2]
        if msg == 'offline':
            if mplayer in players:
                del players[mplayer]
                rate = 20 - len(players) if 20 - len(players) else 1
        if msg == 'online':
            players[mplayer] = 1 #TODO: this should be done in an array, not a dict
            rate = 20 - len(players) if 20 - len(players) else 1
    elif topic.endswith("/message"):
        toplay = [int(x) for x in msg] + [0]

timer = machine.Timer(3)
timer.init(period=100, mode=machine.Timer.PERIODIC, callback=blink)

startupwifi()
playmessage("WELCOME TO MORSE")

timer = machine.Timer(2)
timer.init(period=25, mode=machine.Timer.PERIODIC, callback=player)

machineid = str(binascii.hexlify(system.machine.unique_id()), 'ascii')
c = MQTTClient("umqtt"+machineid, SERVER_IP)

c.set_callback(sub_cb)
c.set_last_will("/morse/"+machineid+"/available", "offline", retain=False)

if c.connect() == 0:
    audio.play('/apps/mqtt_button/connect_mqtt.mp3')
else:
    audio.play('/apps/mqtt_button/fail_connect_mqtt.mp3')

c.subscribe("/morse/#")
c.publish("/morse/"+machineid+"/available", "online", True)

keypad.add_handler(on_key)

touchpads.on(touchpads.RIGHT, vol_up)
touchpads.on(touchpads.LEFT, vol_down)
touchpads.on(touchpads.CANCEL, cancelmsg)
