import time
import Adafruit_BBIO.GPIO as GPIO
import Adafruit_BBIO.PWM as PWM

class Keypad():
    def __init__(self):
        # CONSTANTS 
        self.KEYPAD = [
            ["1","2","3"],
            ["4","5","6"],
            ["7","8","9"],
            ["*","0","#"]
        ]

        self.ROW         = ["P8_8", "P8_10", "P8_12", "P8_14"]
        self.COLUMN      = ["P8_16", "P8_17", "P8_18"]
        self.PASS = "1234"

        for r in self.ROW:
            GPIO.setup(r, GPIO.OUT)
        for c in self.COLUMN:
            GPIO.setup(c, GPIO.IN)
     
    def getKey(self):
        for i in self.ROW:
            GPIO.output(i, GPIO.HIGH)
        for c in self.COLUMN:
            GPIO.add_event_detect(c, GPIO.RISING)

        time.sleep(1)
        print("pls enter key")
        while True:
            for c in self.COLUMN:
                if GPIO.event_detected(c):
                    key = self.identifyKey(c)
                    if key:
                        for c in self.COLUMN:
                            GPIO.remove_event_detect(c)
                        return key
            print("refreshing")
            time.sleep(0.1)
                
    def identifyKey(self, pin):
        print("identifyKey called")
        col = COLUMN.index(pin)
        key = None

        # GPIO.output(self.ROW[0], GPIO.HIGH)
        GPIO.output(self.ROW[1], GPIO.LOW)
        GPIO.output(self.ROW[2], GPIO.LOW)
        GPIO.output(self.ROW[3], GPIO.LOW)
        if GPIO.input(pin):
            key=self.KEYPAD[0][col]

        GPIO.output(self.ROW[0], GPIO.LOW)
        GPIO.output(self.ROW[1], GPIO.HIGH)
        # GPIO.output(self.ROW[2], GPIO.LOW)
        # GPIO.output(self.ROW[3], GPIO.LOW)
        if GPIO.input(pin):
            key=KEYPAD[1][col]


        # GPIO.output(self.ROW[0], GPIO.LOW)
        GPIO.output(self.ROW[1], GPIO.LOW)
        GPIO.output(self.ROW[2], GPIO.HIGH)
        # GPIO.output(self.ROW[3], GPIO.LOW)
        if GPIO.input(pin):
            key=KEYPAD[2][col]

        # GPIO.output(self.ROW[0], GPIO.LOW)
        # GPIO.output(self.ROW[1], GPIO.LOW)
        GPIO.output(self.ROW[2], GPIO.LOW)
        GPIO.output(self.ROW[3], GPIO.HIGH)
        if GPIO.input(pin):
            key=KEYPAD[3][col]

        GPIO.output(self.ROW[0], GPIO.HIGH)
        GPIO.output(self.ROW[1], GPIO.HIGH)
        GPIO.output(self.ROW[2], GPIO.HIGH)
        GPIO.output(self.ROW[3], GPIO.HIGH)
        
        if key:
            return key
         
    def verify_pass(self, pass_entered):
        return pass_entered == self.PASS

class IR:
    def __init__(self, pin, rot, laut, keypad):
        self.pin = pin
        self.rot = rot
        self.laut = laut
        self.keypad = keypad
        GPIO.setup(self.pin, GPIO.IN)
        GPIO.add_event_detect(self.pin, GPIO.RISING, callback=self.cb_ir)

    def __del__(self):
        print("IR {} deleted.".format(self.pin))
        GPIO.remove_event_detect(self.pin)

    def cb_ir(self, pin):
        print("cb_ir called.")
        self.rot.start()
        time.sleep(1)
        self.laut.start()
        time.sleep(1)
        print("pls enter pass to stop alarm")
        start_time = time.time()
        pass_entered = ""
        digit = None
        while True:
            while not digit and time.time()-start_time < 50:
                digit = self.keypad.getKey()
            if digit:
                pass_entered = pass_entered + digit
            print("{} digit(s) already entered".format(len(pass_entered)))
            digit = None
            if len(pass_entered) >= 4:
                if self.keypad.verify_pass(pass_entered[-4:]):
                    print("alarm cancelled")
                    time.sleep(1)
                    self.rot.stop()
                    time.sleep(1)
                    self.laut.stop()
                    time.sleep(1)
                else:
                    print("wrong password")
                    pass_entered = ""
            if time.time() - start_time > 50:
                print("took too long, reset")
                pass_entered = ""
            if time.time() - start_time > 60:
                print("60s passed, quit for test")
                time.sleep(1)
                self.rot.stop()
                time.sleep(1)
                self.laut.stop()
                time.sleep(1)
                break

class LAUT:
    def __init__(self, pin, pwm_perc=50, pwm_freq=10000):
        self.pin = pin
        self.pwm_perc = pwm_perc
        self.pwm_freq = pwm_freq
        GPIO.setup(self.pin, GPIO.OUT)

    def __del__(self):
        print("PWM {} deleted.".format(self.pin))

    def start(self):
        PWM.start(self.pin, self.pwm_perc, self.pwm_freq)

    def stop(self):
        PWM.stop(self.pin)


class ROT():
    def __init__(self, pin, pwm_perc=50, pwm_freq=1):
        self.pin = pin
        self.pwm_perc = pwm_perc
        self.pwm_freq = pwm_freq

    def __del__(self):
        print("ROT {} deleted.".format(self.pin))

    def start(self):
        PWM.start(self.pin, self.pwm_perc, self.pwm_freq)
    
    def stop(self):
        PWM.stop(self.pin)

if __name__ == "__main__":
    rot = ROT("P9_14")
    laut = LAUT("P8_13")
    keypad = Keypad()
    ir = IR("P9_12", rot, laut, keypad)
    try:
        while True:
            print("...")
            time.sleep(2)
    except Exception as e:
        GPIO.cleanup()
        PWM.cleanup()
        print(e)    
