#!/usr/bin/python3
import RPi.GPIO as GPIO
import turtle
"""
Ought to set up limits in screen size and x,y boundaries.
explore tracer function
"""
# Setup GPIO
clearBtn = 12
liftBtn  = 16
ColorBtn = 20

# GPIO pins for the encoders
encoder1_pins = (24, 23)  # A and B pins for encoder 1 (x-axis)
encoder2_pins = (14, 15)  # A and B pins for encoder 2 (y-axis)

GPIO.setmode(GPIO.BCM)
GPIO.setup(clearBtn, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(liftBtn, GPIO.IN) #, pull_up_down=GPIO.PUD_UP #removal of this means you must hold the button down
GPIO.setup(ColorBtn, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(encoder1_pins[0], GPIO.IN) #removed PUD_UP as encoders are not PWM, and resistors are included.
GPIO.setup(encoder1_pins[1], GPIO.IN)
GPIO.setup(encoder2_pins[0], GPIO.IN)
GPIO.setup(encoder2_pins[1], GPIO.IN)

# Variables to store encoder state
encoder1_last_state = (GPIO.input(encoder1_pins[0]) << 1) | GPIO.input(encoder1_pins[1])
encoder2_last_state = (GPIO.input(encoder2_pins[0]) << 1) | GPIO.input(encoder2_pins[1])

# Encoder positions
x_coord  = 0
y_coord  = 0

penState = False  # False for pen down, True for pen up
i = 0             # index of current color

# Set up the turtle screen
screen = turtle.Screen()
screen.tracer(0)
screen.setup(width=1.0, height=1.0)  # Set the window to full-screen mode
canvas = screen.getcanvas()

# Create a RawTurtle object with the canvas
raw_turtle = turtle.RawTurtle(canvas)
raw_turtle.shape('circle')
raw_turtle.shapesize(0.5)  # Cursor size: 0.5 is half of normal
raw_turtle.width(6)        # Line width
raw_turtle.speed(0)

#BUTTON FUNCTIONS
    
#toggle though colors 
def Change_Color(channel):
    global i
    colors = [(1, 0, 0), (0, 1, 0), (0, 0, 1), (0, 1, 1), (1, 0, 1), (1, 1, 0), (1, 1, 1), (0, 0, 0)]  # List of RGB colors
    raw_turtle.pencolor(colors[i % len(colors)])  # Set pen color based on the current index of the length of the color list
    i += 1

def ClearScrnBtn(channel):
    global x_coord, y_coord #,oldX, oldY
    raw_turtle.reset()  # Reset the turtle, resets everything including point size
    raw_turtle.shapesize(0.5)  # Cursor size: 0.5 is half of normal
    raw_turtle.width(6)
    x_coord = 0
    y_coord = 0
    screen.tracer(0)

# Callback function to lift or lower the pen
def lift_pen(channel):
    global penState
    penState = not penState
    if penState:
        raw_turtle.penup()
    else:
        raw_turtle.pendown()


# Callback function for encoder 1 (x-axis)
def encoder1_callback(channel):
    global encoder1_last_state, x_coord
    a = GPIO.input(encoder1_pins[0])
    b = GPIO.input(encoder1_pins[1])
    new_state = (a << 1) | b
    if (encoder1_last_state == 0b00 and new_state == 0b10) or (encoder1_last_state == 0b11 and new_state == 0b01):
        x_coord += 6        
    elif (encoder1_last_state == 0b10 and new_state == 0b00) or (encoder1_last_state == 0b01 and new_state == 0b11):
        x_coord -= 6
    encoder1_last_state = new_state

# Callback function for encoder 2 (y-axis)
def encoder2_callback(channel):
    global encoder2_last_state, y_coord
    a = GPIO.input(encoder2_pins[0])
    b = GPIO.input(encoder2_pins[1])
    new_state = (a << 1) | b
    if (encoder2_last_state == 0b00 and new_state == 0b10) or (encoder2_last_state == 0b11 and new_state == 0b01):
        y_coord -= 6
    elif (encoder2_last_state == 0b10 and new_state == 0b00) or (encoder2_last_state == 0b01 and new_state == 0b11):
        y_coord += 6
    encoder2_last_state = new_state



# Add event detection for encoder 1 (x-axis)
GPIO.add_event_detect(encoder1_pins[0], GPIO.BOTH, callback=encoder1_callback,bouncetime=15)
GPIO.add_event_detect(encoder1_pins[1], GPIO.BOTH, callback=encoder1_callback,bouncetime=15)

# Add event detection for encoder 2 (y-axis)
GPIO.add_event_detect(encoder2_pins[0], GPIO.BOTH, callback=encoder2_callback,bouncetime=15)
GPIO.add_event_detect(encoder2_pins[1], GPIO.BOTH, callback=encoder2_callback,bouncetime=15)

# Add event listener to the button pins
GPIO.add_event_detect(clearBtn, GPIO.FALLING, callback=ClearScrnBtn, bouncetime=300)
GPIO.add_event_detect(liftBtn,  GPIO.FALLING, callback=lift_pen,     bouncetime=300)
GPIO.add_event_detect(ColorBtn, GPIO.FALLING, callback=Change_Color, bouncetime=300)

def update_position():
    global x_coord, y_coord 
    screen.title(f"X: {x_coord}, Y: {y_coord}")
    #raw_turtle.goto(x_coord, y_coord)		
    raw_turtle.setx(x_coord)
    raw_turtle.sety(y_coord)

    if(GPIO.event_detected(encoder1_pins[0]) or GPIO.event_detected(encoder1_pins[1]) or GPIO.event_detected(encoder2_pins[0]) or GPIO.event_detected(encoder1_pins[1])):
        screen.ontimer(update_position, 100)
    else: 
        screen.ontimer(update_position, 100)

# Start updating the position
update_position()

# Start the turtle main loop
#turtle.mainloop()
screen.mainloop()

# Clean up GPIO on keyboard interrupt
GPIO.cleanup()
#turtle.done()   #not mentioned in turtle documentation for raw

