import os
import sys
import board
import time
import busio
import digitalio
import terminalio
import storage

# import display libraries
import displayio
import vectorio # for shapes
import adafruit_ili9341 # TFT (thin film transistor) display
from adafruit_display_text.bitmap_label import Label
from adafruit_display_text import label
from adafruit_display_shapes.rect import Rect
#from adafruit_display_shapes.circle import Circle
#from adafruit_display_shapes.triangle import Triangle
#from adafruit_display_shapes.line import Line
from adafruit_stmpe610 import Adafruit_STMPE610_SPI # touch screen reader

import adafruit_as726x      # visible spectrum

# set constants

SCREENSIZE_X = const(320)
SCREENSIZE_Y = const(240)
ON = const(0)  #indicator LED and auxiliary lamp controls are active low.
OFF = const(1)

def main():
    # initialize touch screen and display screen
    spi_bus = initialize_spi()
    display = initialize_display( spi_bus )
    touch_screen = initialize_touch_screen( spi_bus )

    # initialize table display group
    display_group_table = initialize_display_group( display )
    text_group = create_table_screen( display, display_group_table )
    display.show( display_group_table )

    # initialize devices
    i2c_bus = initialize_i2c()
    uart_bus = initialize_uart()
    #indicator = initialize_indicator()
    VIS_sensor = initialize_VIS_sensor( i2c_bus )
    NIR_sensor = initialize_NIR_sensor( uart_bus )
    aux_lamp = initialize_auxilliary_lamp()

    number_of_source_lamps_states = 2
    source_lamps_state = 0
    last_source_lamps_state = 0
    source_lamps_last_press_state = False

    while True:

        if source_lamps_state == 0:
            print("lamp_sources_off")
            lamp_sources_off(VIS_sensor, NIR_sensor, aux_lamp)
        else:
            print("lamp_sources_on")
            lamp_sources_on(VIS_sensor, NIR_sensor, aux_lamp)


        exit_wait = 0
        remaining_wait_time = 2
        while remaining_wait_time > 0 and exit_wait == 0:

            press = [0,0]
            press = screen_pressed( touch_screen )

            if press[1] != source_lamps_last_press_state and press[1] == True:
                source_lamps_changed = True
                source_lamps_state = (source_lamps_state + 1) % number_of_source_lamps_states
            source_lamps_last_press_state = press[1]

            remaining_wait_time = 0
            time.sleep( 0.1 )
        # return to top of infinite loop

# function definitions below

def initialize_spi():
    try:
        # spi has already been initialized by displayio/adafruit_ili9341, but reinitialize it here anyway
        spi_bus = board.SPI()
        # initialized spi bus
        return spi_bus
    except ValueError as err:
        print( "Error: spi bus fail: {:}".format(err) )
        return False

def initialize_touch_screen( spi_bus ):
    touch_screen_chip_select = digitalio.DigitalInOut(board.D6)
    try:
        touch_screen = Adafruit_STMPE610_SPI(spi_bus, touch_screen_chip_select)
        return touch_screen
    except ValueError as err:
        print("Error: touch screen fail {:}".format(err))
        return False

def screen_pressed( touch_screen ):
    record_pause_press_state = 0
    table_graph_press_state = 0
    source_lamp_press_state = 0
    while not touch_screen.buffer_empty:
        touch_data = touch_screen.read_data()
        touch_x = touch_data[ 1 ]
        touch_y = touch_data[ 0 ]
        touch_pressure = touch_data[ 2 ]
        #print( "X: %d, Y: %d, press: %d" % ( touch_x, touch_y, touch_pressure ) )
        if ( touch_x < 2000 ) and ( touch_y > 1500) and ( touch_y < 3600 ) and ( touch_y > 2400 ): #1750, 2950
            #print ("record_pause_press_state = 1")
            record_pause_press_state = 1
        if ( touch_x > 1300 ) and ( touch_y < 2000 ) and ( touch_y < 2000 ): #1800, 1100
            source_lamp_press_state = 1
            #print("lamp control pushed")
        #if ( touch_x < 1000 ) and ( touch_y > 1000 ) and ( touch_y < 3000 ):
        #    table_graph_press_state = 1
    return (record_pause_press_state, source_lamp_press_state)

def initialize_display( spi_bus ):
    if spi_bus == False:
        return False
    try:
        # displayio/dafruit_ili9341 library owns the pins until display release
        displayio.release_displays()
        tft_display_cs = board.D9
        tft_display_dc = board.D10
        display_bus = displayio.FourWire( spi_bus, command=tft_display_dc, chip_select=tft_display_cs )
        display = adafruit_ili9341.ILI9341( display_bus, width=SCREENSIZE_X, height=SCREENSIZE_Y, rotation=180 )
        # initialized display
        return display
    except ValueError as err:
        print("Error: display fail {:}".format(err))
        return False

def initialize_display_group( display ):
    if display == False:
        print("no display")
        return False
    display_group = displayio.Group()
    return display_group

def create_table_screen( display, display_group ):
    RED = 0xFF0022
    full_spectrum_frame( display_group, RED )
    text_group = full_spectrum_text_groups( display_group )
    return text_group

def full_spectrum_frame( table_group, border_color ):
    # begin full spectrum frame
    if table_group == False:
        return
    palette = displayio.Palette(1)
    palette[0] = border_color
    background_rectangle = vectorio.Rectangle(pixel_shader=palette, width=SCREENSIZE_X, height=SCREENSIZE_Y, x=0, y=0)
    table_group.append( background_rectangle )
    palette = displayio.Palette(1)
    palette[0] = 0xFFFFFF
    border_width = 7
    foreground_rectangle = vectorio.Rectangle(pixel_shader=palette, width=SCREENSIZE_X - 2*border_width, height=SCREENSIZE_Y - 2*border_width, x=border_width, y=border_width)
    table_group.append( foreground_rectangle )



    palette = displayio.Palette(1)
    palette[0] = 0xC1C1C1
    if False:
        #Draw screen switch button:
        screen_button_triangle = vectorio.Polygon( pixel_shader=palette, points = [(250, 60), (250, 160), (310, 110)], x=0, y=0)
        table_group.append(screen_button_triangle)

        #Draw the record_pause_circle:
        record_pause_circle = vectorio.Circle( pixel_shader=palette, radius=45, x=170, y=70 )
        table_group.append( record_pause_circle )

    #Draw source trapezoid
    source_trapezoid = vectorio.Polygon( pixel_shader=palette, points = [(150, 170), (190, 170), (210, 230), (130, 230)], x=0, y=0)
    table_group.append(source_trapezoid)


def full_spectrum_text_groups( table_group ):
    if table_group == False:
        return False
    # Fixed width font
    fontPixelWidth, fontPixelHeight = terminalio.FONT.get_bounding_box()
    text_color = 0x000000 # black text for readability
    text_group = displayio.Group( scale = 2, x = 15, y = 20 ) #scale sets the text scale in pixels per pixel
    table_group.append( text_group )
    #print("TG max_size {:}".format(len(text_group))) # to figure max_size of group
    return text_group

def initialize_i2c():
    # Initialize the i2c bus at 100kHz, the fastest speed the tir sensor will accommodate.
    # Default i2c speed is 400kHz. At that speed, the TIR sensor will fail to communicate.
    try:
        i2c_bus = busio.I2C( board.SCL, board.SDA, frequency=100000 )
        # initialized i2c bus
        return i2c_bus
    except ValueError as err:
        print( "Error: i2c bus fail: {:}".format(err) )
        return False

def initialize_uart():
    try:
        uart_bus = busio.UART(board.TX, board.RX, baudrate=115200, bits=8, parity=1, stop=1)
        # initialized uart bus
        return uart_bus
    except ValueError as err: # known error behavior
        print( "Error: uart bus fail: {:}".format(err) )
        return False

def initialize_indicator():
    try:
        indicator_LED = digitalio.DigitalInOut( board.A0 )
        indicator_LED.direction = digitalio.Direction.OUTPUT
        indicator_LED.value = True #active low, True is off
        # initialized indicator
        return indicator_LED
    except Exception as err: # TBD: identify some typcial errors
        print( "Error: led pin init failed {:}".format(err) )
        return False

def initialize_auxilliary_lamp():
    try:
        aux_lamp = digitalio.DigitalInOut( board.A0 ) #D4 )
        aux_lamp.direction = digitalio.Direction.OUTPUT
        aux_lamp.value = True #active low, True is off
        # initialized indicator
        return aux_lamp
    except Exception as err: # TBD: identify some typcial errors
        print( "Error: auxilliary lamp control pin init failed {:}".format(err) )
        return False

def initialize_VIS_sensor( i2c_bus ):
    if i2c_bus == False:
        return False
    try:
        VIS_sensor = adafruit_as726x.AS726x_I2C( i2c_bus )
        VIS_sensor.conversion_mode = VIS_sensor.MODE_2
        # initialized visible spectrum sensor
        #TBD why 16 gain and 166 ms integration time? Because those are the values during the sensor calibration.
        VIS_sensor.gain = 16
        VIS_sensor.integration_time = 166
        return VIS_sensor
    except ValueError as err:
        print( "Error: visible spectrum sensor fail: {:}".format(err) )
        return False

def initialize_NIR_sensor( uart_bus ):
    if uart_bus == False:
        return False
    uart_bus.write(b"AT\n")
    data = uart_bus.readline() #typical first response from the device is b'ERROR\n', which indicates it is present.
    if data is None:
        print ( "Error: near infrared spectrum sensor fail" )
        return False
    else:
        # initialized near infrared spectrum sensor
        # check gain setting
        b = b"ATGAIN\n"
        uart_bus.write(b)
        data = uart_bus.readline()
        #print ( "# NIR spectrum default GAIN (2 = 16x gain): {:}".format(data))
        #check integration time setting
        b = b"ATINTTIME\n"
        uart_bus.write(b)
        data = uart_bus.readline()
        # print( "# NIR spectrum default INTTIME (59 * 2.8ms = 165ms): {:}".format(data))
        return uart_bus

def lamp_sources_on(VIS_sensor, NIR_sensor, aux_lamp):
    if aux_lamp != None:
        aux_lamp.value = ON

    if VIS_sensor != None:
        VIS_sensor.driver_led_current = 12.5 # mA, options 12.5, 25, 50, 100 mA
        VIS_sensor.driver_led = True

    if NIR_sensor != None:
        s = "ATLEDC=48\n"   #0, 16, 32, 48 set the driver to 12.5, 25, 50, 100 mA
        b = bytearray()
        b.extend(s)
        NIR_sensor.write(b)
        #print( "Bytearray sent: %s" % b )
        data = NIR_sensor.readline()
        #print( "Data received: %s" % data)
        s = "ATLED1=100\n" #100 is on, 0 is off
        b = bytearray()
        b.extend(s)
        NIR_sensor.write(b)
        #print( "Bytearray sent: %s" % b )
        data = NIR_sensor.readline()
        #print( "Data received: %s" % data)

def lamp_sources_off(VIS_sensor, NIR_sensor, aux_lamp):
    if aux_lamp != None:
        aux_lamp.value = OFF
    if VIS_sensor != None:
        VIS_sensor.driver_led = False
    if NIR_sensor != None:
        s = "ATLED1=0\n" #100 is on, 0 is off
        b = bytearray()
        b.extend(s)
        NIR_sensor.write(b)
        #print( "Bytearray sent: %s" % b )
        data = NIR_sensor.readline()
        #print( "Data received: %s" % data)

main()

