import board, time, digitalio
import neopixel
from audiomp3 import MP3Decoder
from audiopwmio import PWMAudioOut as AudioOut

#constant values
MAX_STEPS = 512 #full rotation
OPEN_RATIO = 3/4 #frac rotation for track

# stepper motors setup (defining control pins)
# GP2 - GP5
pinsA = [
    digitalio.DigitalInOut(board.GP2),
    digitalio.DigitalInOut(board.GP3),
    digitalio.DigitalInOut(board.GP4),
    digitalio.DigitalInOut(board.GP5)
]
# GP6 - GP9
pinsB = [
    digitalio.DigitalInOut(board.GP6),
    digitalio.DigitalInOut(board.GP7),
    digitalio.DigitalInOut(board.GP8),
    digitalio.DigitalInOut(board.GP9)
]
# GP10 - GP13
pinsC = [
    digitalio.DigitalInOut(board.GP10),
    digitalio.DigitalInOut(board.GP11),
    digitalio.DigitalInOut(board.GP12),
    digitalio.DigitalInOut(board.GP13)
]

# set each pin to output mode
for p in pinsA + pinsB + pinsC:
    p.direction = digitalio.Direction.OUTPUT

# define the stepper motor sequence
# one loop through will increment gear one tick
step_sequence = [
    [1, 0, 0, 0],
    [1, 1, 0, 0],
    [0, 1, 0, 0],
    [0, 1, 1, 0],
    [0, 0, 1, 0],
    [0, 0, 1, 1],
    [0, 0, 0, 1],
    [1, 0, 0, 1]
]

# audio setup
audio = AudioOut(board.GP19)
path = "sounds/"
mp3_file = open(path + "zelda.mp3", "rb")
decoder = MP3Decoder(mp3_file)

def play_mp3(filename):
    decoder.file.close()  # close any previously open file
    decoder.file = open(path + filename, "rb")
    audio.play(decoder)

# loops through the step sequence to move the gear one tick
def step_motor(direction, delay, pins):
    # adjusts if loop forward (1) or backward (1) w/ direction
    for step in range(len(step_sequence))[::direction]:
        for pin in range(4):
            pins[pin].value = step_sequence[step][pin]
        time.sleep(delay)

def withdraw(pins, ratio):
    for i in range(int(MAX_STEPS * ratio)):
        step_motor(1, 0.001, pins)

def close(pins, ratio):
    for i in range(int(MAX_STEPS * ratio)):
        step_motor(-1, 0.001, pins)

#neopixel setup
lights = neopixel.NeoPixel(board.GP28, 50)
lights.fill(0x000000)
lightA = 9
lightB = 6
lightC = 3

#button setup - buttons return false when pressed
buttonA = digitalio.DigitalInOut(board.GP27)
buttonA.switch_to_input(pull=digitalio.Pull.UP)

buttonB = digitalio.DigitalInOut(board.GP26)
buttonB.switch_to_input(pull=digitalio.Pull.UP)

buttonC = digitalio.DigitalInOut(board.GP22)
buttonC.switch_to_input(pull=digitalio.Pull.UP)

buttonDEMO = digitalio.DigitalInOut(board.GP20)
buttonDEMO.switch_to_input(pull=digitalio.Pull.UP)

# main
print("code start")

while True:
    if not buttonA.value:
        print("a pressed")
        lights.fill(0xFF0000)
        lights[lightB] = 0x000000
        lights[lightC] = 0x000000
        play_mp3("zelda.mp3")
        withdraw(pinsA, 22/32)
        time.sleep(2)
        close(pinsA, 22/32)
    elif not buttonB.value:
        lights.fill(0x00FF00)
        lights[lightA] = 0x000000
        lights[lightC] = 0x000000
        play_mp3("zelda.mp3")
        withdraw(pinsB, OPEN_RATIO)
        time.sleep(2)
        close(pinsB, OPEN_RATIO)
    elif not buttonC.value:
        lights.fill(0x0000FF)
        lights[lightA] = 0x000000
        lights[lightB] = 0x000000
        play_mp3("zelda.mp3")
        withdraw(pinsC, OPEN_RATIO)
        time.sleep(2)
        close(pinsC, OPEN_RATIO)
    elif not buttonDEMO.value:
        lights.fill(0xFF0000)
        lights[lightB] = 0x000000
        lights[lightC] = 0x000000
        time.sleep(3)
        lights.fill(0x00FF00)
        lights[lightA] = 0x000000
        lights[lightC] = 0x000000
        time.sleep(3)
        lights.fill(0x0000FF)
        lights[lightA] = 0x000000
        lights[lightB] = 0x000000
        time.sleep(3)
    else:
        lights.fill(0x000000)