"""View images from the EMF 2018 time-lapse camera
"""
___title___        = "Lobster Vision"
___license___      = "MIT"
___dependencies___ = ["app", "dialogs", "wifi", "buttons", "http", "ugfx_helper"]
___categories___   = ["Other"]

import ugfx, wifi, dialogs, utime, ugfx_helper, buttons
import gc
from http import *
from tilda import Buttons

IMAGE_PROXY     = 'http://imageproxy.lobsterdev.com/api/'
ACCESS_KEY      = 'ZW1mMjAxODplbWYyMDE4'
FULL_MONTHS     = ['January', 'February', 'March', 'April', 'May', 'June',
                   'July', 'August', 'September', 'October', 'November',
                   'December']
DAYS            = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday',
                   'Saturday', 'Sunday']

PHOTO_FILE      = 'lobstervision/photo.gif'
projects = []
selectedProject = 0
selectedCamera = 0
selectedDate = None
selectedTime = None
imageList = []
imageIndexWithinDate = None
filename = None

def loading_screen():
    logo = 'lobstervision/lobsterpictures.gif'
    ugfx.area(0,0,ugfx.width(),ugfx.height(),0xFFFF)
    ugfx.display_image(0,50,logo)
    ugfx.set_default_font(ugfx.FONT_SMALL)
    ugfx.text(15, 305, "lobstervision.tv/emf2018", ugfx.GREY)
    display_loading()

def display_error(message):
    dialogs.notice(message, title='Error')

def display_loading():
    ugfx.area(0,215,320,25,0xFFFF)
    ugfx.set_default_font(ugfx.FONT_MEDIUM_BOLD)
    ugfx.text(90,220, "Loading...", ugfx.GREY)

def display_datetime():
    ugfx.area(0,215,320,25,0xFFFF)
    ugfx.set_default_font(ugfx.FONT_MEDIUM_BOLD)
    (date, day) = format_selected_date()
    time = format_selected_time()
    ugfx.text(5,220, time, ugfx.RED)
    ugfx.text(60,220, "%s, %s" % (day, date), ugfx.GREY)

def display_image():
    gc.collect()
    global selectedProject, selectedCamera, filename
    display_loading()
    endpoint = 'images/project/%d/camera/%d/%s' % \
            (selectedProject, selectedCamera, filename)
    try:
        headers = {'Authorization': 'Basic '+ACCESS_KEY}
        url = IMAGE_PROXY+endpoint
        get(url, headers = headers).raise_for_status().download_to(PHOTO_FILE)
    except OSError as e:
        display_error('Unable to download image %s' % e)
        return
    utime.sleep_ms(200)
    ugfx.display_image(0,0,PHOTO_FILE)
    display_datetime()

def format_selected_date():
    date = None
    day = None
    global selectedDate
    (year, month, day, hour, minute, second, dayofweek,
     dayinyear) = utime.localtime(selectedDate - 946684800)
    date = '%d %s %d' % (day, FULL_MONTHS[month-1], year)
    day = DAYS[dayofweek]
    return (date, day)

def format_selected_time():
    global selectedTime
    time = str(selectedTime)
    return '%s:%s' % (time[:2], time[2:4])

def list_cameras():
    global selectedProject
    cameraCount = len(projects[selectedProject]['camera'])
    cameras = []
    for i in range(0, cameraCount):
        cameras.append({'index': i, 'title': 'Camera %d' % (i + 1)})
    return cameras

def get_from_api(path):
    headers = {'Authorization': 'Basic '+ACCESS_KEY}
    url = IMAGE_PROXY+path
    with get(url, headers = headers) as response:
        return response.json()

def load_account_details():
    gc.collect()
    rsp = get_from_api('account')
    global projects
    if not 'result' in rsp:
        raise OSError('Could not load account data')
    if 'client' in rsp['result']:
        projects = rsp['result']['client']['project']

def load_camera_dates():
    gc.collect()
    for p, project in enumerate(projects):
        for c, camera in enumerate(project['camera']):
            endpoint = 'dates/project/%d/camera/%d' % (p, c)
            try:
                rsp = get_from_api(endpoint)
            except OSError:
                continue
            if not 'result' in rsp:
                continue
            camera['start'] = rsp['result']['start']
            camera['finish'] = rsp['result']['finish']
            camera['missing'] = rsp['result']['disabled']

def load_image_list():
    gc.collect()
    global selectedProject, selectedCamera, selectedDate, selectedTime, imageList
    if not selectedDate:
        # Bodge as EMF camera seems to have stalled uploading due to lack of
        # signal
        if projects[selectedProject]['camera'][selectedCamera]['finish'] == 1535673600:
           selectedDate = 1535587200
           selectedTime = "150000"   
        else:
           selectedDate = projects[selectedProject]['camera']\
                            [selectedCamera]['finish']
    endpoint = 'dates/project/%d/camera/%d/%s' % \
                (selectedProject, selectedCamera, selectedDate)
    try:
        rsp = get_from_api(endpoint)
    except OSError:
        return
    if not 'result' in rsp:
        return
    imageList = rsp['result']
    select_from_image_list()

def select_from_image_list():
    global imageList, selectedTime, imageIndexWithinDate, filename
    selectedImage = None
    firstImage = imageList[0]
    lastImage = imageList[-1]
    if not selectedTime or selectedTime >= lastImage['time']:
        selectedImage =  lastImage
        imageIndexWithinDate = len(imageList) - 1
    elif selectedTime <= firstImage['time']:
        selectedImage = firstImage
        imageIndexWithinDate = 0
    else:
        previousDiff = 0
        for position, image in enumerate(imageList):
            diff = abs(int(image['time']) - int(selectedTime))
            if selectedTime < image['time']:
                if diff < previousDiff:
                    selectedImage = image
                    imageIndexWithinDate = position
                else:
                    selectedImage = imageList[position - 1]
                    imageIndexWithinDate= position - 1
                break
            previousDiff = diff
        if not selectedImage:
            selectedImage = lastImage
            imageIndexWithinDate = len(imageList) - 1
    selectedTime = selectedImage['time']
    filename = selectedImage['image']
    display_image()

def select_camera(camera):
    global selectedCamera, selectedDate, selectedTime
    selectedCamera = int(camera)
    selectedDate = None
    selectedTime = None
    load_image_list()

def select_date(date):
    global selectedDate
    selectedDate = int(date)
    load_image_list()

def previous_date():
    global selectedProject, selectedCamera, selectedDate
    camera = \
        projects[selectedProject]['camera'][selectedCamera]
    date = selectedDate - 86400 # 24 hours
    # Check not trying to go back before the camera's first day
    if date < camera['start']:
        return
    # Skip over any missing dates
    while date in camera['missing']:
        camera -= 86400
    print("Setting date to %s" % date)
    selectedDate = date
    load_image_list()

def next_date():
    global selectedProject, selectedCamera, selectedDate
    camera = \
        projects[selectedProject]['camera'][selectedCamera]
    date = selectedDate + 86400 # 24 hours
    # Check not trying to go back past the camera's last day
    if date > camera['finish']:
        return
    # Skip over any missing dates
    while date in camera['missing']:
        camera += 86400
    selectedDate = date
    load_image_list()

def previous_image():
    global selectedProject, selectedCamera, selectedDate, selectedTime
    global imageList, imageIndexWithinDate,  filename
    # If first image of current day, jump to last image of previous day
    if imageIndexWithinDate == 0:
        camera = \
            projects[selectedProject]['camera'][selectedCamera]
        if selectedDate != camera['start']:
            selectedTime = None
            previous_date()
        return
    imageIndexWithinDate -= 1
    image = imageList[imageIndexWithinDate]
    filename = image['image']
    selectedTime = image['time']
    display_image()

def next_image():
    global selectedProject, selectedCamera, selectedDate, selectedTime
    global imageList, imageIndexWithinDate, filename
    # If first image of current day, jump to first image of next day
    if imageIndexWithinDate == len(imageList)-1:
        camera = \
            projects[selectedProject]['camera'][selectedCamera]
        if selectedDate != camera['finish']:
            selectedTime = '000000'
            next_date()
        return
    imageIndexWithinDate += 1
    image = imageList[imageIndexWithinDate]
    filename = image['image']
    selectedTime = image['time']
    display_image()


def start():
    ugfx_helper.init()
    loading_screen()
    if not wifi.is_connected():
        try:
            wifi.connect()
        except OSError:
            display_error("Unable to connect to Wifi")
            return False
    try:
        load_account_details()
    except OSError as e:
        display_error("Unable to contact the server. Please try again later")
        return False
    if len(projects) == 0:
        display_error("Sorry, no projects are available to display")
        return False
    load_camera_dates()
    load_image_list()
    return True

running = start()
while running:
    if buttons.is_triggered(Buttons.JOY_Right):
        next_image()
    elif buttons.is_triggered(buttons.Buttons.JOY_Left):
        previous_image()
    elif buttons.is_triggered(Buttons.JOY_Up):
        previous_date()
    elif buttons.is_triggered(Buttons.JOY_Down):
        next_date()
    utime.sleep_ms(30)
