################################## IMPORT ##################################
from gpiozero import Button
from signal import pause
from subprocess import check_call
import random as rd
import json
import numpy as np
from time import sleep
from LCD import LCD
import os
import sys

################################## SET-UP (beginning) ##################################
lcd = LCD(2, 0x27, True) #'Starting' the screen
lcd.message('     ALIVE!',1)
lcd.message('Start-up...',2)

################################## MARKOV PART ##################################

with open("data_MM2.json", "r") as read_file:
    MM2 = json.load(read_file)

def generate_line():
    line = []
    key = ['', 'START']
    while key[1] != 'STOP':
        used_key = ' '.join(key)
        new_word = rd.choices(MM2[used_key][0], weights = MM2[used_key][1])[0]
        if new_word == 'STOP':
            return line
        line.append(new_word)
        key.append(new_word)
        key.pop(0)

r_fit = [np.array([1.14817765e+02, 5.28687653e-02]),
         np.array([2.2190698 , 0.02821746]),
         np.array([0.50054963, 0.03734326]),
         np.array([2.50091145e-14, 1.21042097e+00])]

def fNb(n,N,r):
    return N*(np.exp(-1*r*n))

def get_p(n):
    p = []
    for i in range(4):
        p.append(fNb(n, *r_fit[i]))
    p = np.array(p)
    return p/np.sum(p)

def nb_burps(n):
    return rd.choices([0,1,2,3], get_p(n))[0]

def include_burps():
    line = generate_line()
    N = nb_burps(len(line))
    for _ in range(N):
        pos = rd.randint(0, len(line))
        line = line[:pos] + ['*burps*'] + line[pos:]
    return line

def generate():
    return ' '.join(include_burps())

################################## SCREEN PART ##################################

L = 16 # /!\ need to change that value if you have another screen width 

def resize_word(sentence): #cut the word if too long regarding the size of the screen
    nb_words = len(sentence)
    current_word = 0
    while current_word<nb_words:
        word = sentence[current_word]
        if len(word)>L:
            cut_word = []
            for i in range(len(word)//L+1):
                cut_word.append(word[i*L:(i+1)*L])
            sentence = sentence[:current_word] + cut_word + sentence[current_word+1:]
            nb_words = len(sentence)
            current_word += len(cut_word)-1
        current_word += 1
    return sentence

def resize_sentence(sentence): #cut the sentence into bits according to the size of the screen
    resized = []
    buffer = []
    sentence = resize_word(sentence)
    for current_word in range(len(sentence)):
        buffer.append(sentence[current_word])
        if len(" ".join(buffer))>L:
            resized.append(" ".join(buffer[:-1]))
            buffer = [buffer[-1]]
    resized.append(" ".join(buffer))
    return resized

def display():
    return resize_sentence(include_burps())

def screen():
    prompt=display()
    nb_row = len(prompt)
    for i in range(0, nb_row, 2):
        lcd.message(prompt[i], 1)
        if i+1<nb_row:
            lcd.message(prompt[i+1], 2)
        else:
            lcd.message("", 2)
        sleep(2)
    lcd.clear()

def quick_loop():
    for _ in range(5):
        screen()
        sleep(2)

################################## BUTTONS PART ##################################

press_time = 0.05
new_on = False
is_going = False
auto_on = False

def go_new():
    #print('new')
    global new_on
    if not is_going:
        new_on=True
    #print(new_on)   
        
def go_auto():
    #print('auto')
    global auto_on
    auto_on = not auto_on
    #print(auto_on)

def go_kill():
    #print("kill")
    lcd.message('Restarting...',1)
    lcd.message("", 2)
    sleep(0.1)
    os.execv(sys.executable, ['python'] + sys.argv)
    
def go_off():
    #print("off")
    lcd.message('Switched off.',1)
    lcd.message('      DEAD',2)
    check_call(['sudo', 'poweroff'])

new_btn = Button(6, hold_time=press_time)
auto_btn = Button(13, hold_time=press_time)
kill_btn = Button(19, hold_time=press_time)
off_btn = Button(26, hold_time=press_time)

################################## SET-UP (end) ##################################
lcd.message('Ready!',2)
sleep(1)
lcd.clear()

################################## RUNNING LOOP ##################################
while True:
    new_btn.when_held = go_new
    auto_btn.when_held = go_auto
    kill_btn.when_held = go_kill
    off_btn.when_held = go_off
    
    if auto_on or new_on:
        new_on = False
        is_going = True
        screen()
        is_going = False
        sleep(2)
