import ujson
import utime
import display
import math


class Clock:
    def __init__(self, conf, screen):
        self.last_secs = -1
        self.config = conf
        self.screen = screen
        self.current_event = None
        self.last_day = -1
        
    def tick(self):
        now = utime.localtime()
        one_day = 24 * 60 * 60
        if now[5] != self.last_secs:
            self.last_secs = now[5]
            self.screen.time = '{0:02}:{1:02}:{2:02}'.format(now[3], now[4], now[5])
            day = now[2]
            if day != self.last_day:
                self.last_day = day
                timestamp = utime.mktime(now)
                event = self.config.get_event_from_timestamp(timestamp)
                if event:
                    event_day = math.ceil((timestamp + 1 - event.start_time) / one_day)
                    self.screen.event_day = 'Day {}'.format(event_day)
                    self.screen.set_event(event.name)
                    self.screen.set_event_active(0 < event_day <= event.duration)
                else:
                    self.screen.set_event(None)
                self.screen.week_day = self.config.weekdays[now[6]]
                self.screen.date = '{2:02}.{1:02}.{0:04}'.format(now[0], now[1], now[2])
            self.screen.refresh()


class Screen:
    def __init__(self):
        self.disp = display.open()
        self.event_name = 'no event'
        self.time = '99:99:99'
        self.event_day = 'Day X'
        self.week_day = 'noday'
        self.date = '2999-99-99'
        self.show_event_day = False
        self.event_day_color = display.color.WHITE
        self.event_name_color = display.color.RED
        self._in_event = False
        
    def set_event(self, name):
        if name:
            self.event_name_color = display.color.WHITE
            self.event_name = name
            self._in_event = True
        else:
            self.event_name_color = display.color.RED
            self.event_name = 'No Event'
            self._in_event = False
    
    def set_event_active(self, active):
        if active:
            self.event_day_color = display.color.GREEN
        else:
            self.event_day_color = display.color.RED
    
    def center_text(self, text, line, color=display.color.WHITE):
        start_pos = int(80 - (len(text) / 2) * (160 / 11))
        self.disp.print(text, posx=start_pos, posy=line * 20, fg=color)
        
    def refresh(self):
        self.disp.clear()
        self.center_text(self.event_name, 0, self.event_name_color)
        self.center_text(self.time, 1)
        self.show_event_day = not self.show_event_day
        if self.show_event_day and self._in_event:
            self.center_text(self.event_day, 2, self.event_day_color)
        else:
            self.center_text(self.date, 2)
        self.center_text(self.week_day, 3)
        self.disp.update()
        # ToDo: show battery state, timers etc.
        

class Event:
    def __init__(self, entry):
        self.start_time = None
        self.duration = 1
        self.name = ''
        self.parse_event(entry)
        
    @property
    def end_time(self):
        return self.start_time + (self.duration * 24 * 60 * 60)
    
    def parse_event(self, entry):
        year = entry['year']
        month = entry['month']
        day = entry['day1']
        self.duration = entry['duration']
        self.start_time = utime.mktime((year, month, day, 0, 0, 0, 0, 0))
        self.name = entry['name']
        

class Config:
    def __init__(self, config_data):
        self.events = []
        self.weekdays = config_data['weekdays']
        self.count_before = config_data['settings']['count days before']
        self.count_after = config_data['settings']['count days after']
        
        event_list = config_data['events']
        self.load_events(event_list)
        
    def load_events(self, event_list):
        for entry in event_list:
            event = Event(entry)
            self.events.append(event)

    def get_event_from_timestamp(self, timestamp):
        for event in self.events:
            min_date = event.start_time - (self.count_before * 24 * 60 * 60)
            max_date = event.end_time + (self.count_after * 24 * 60 * 60)
            if min_date <= timestamp <= max_date:
                return event
        return None


def run():
    with open('/apps/Event_Clock/config.json', 'r') as f:
        data = ujson.loads(f.read())
    conf = Config(data)
    scr = Screen()
    clock = Clock(conf, scr)
    while True:
        clock.tick()
        utime.sleep(0.2)


if '__main__' == __name__:
    run()
