# --------------------------------------------------------------------------- #
# Includes
import datetime
import time
import RPi.GPIO as GPIO
from threading import Thread
#from utils.loglib import *
# --------------------------------------------------------------------------- #

# --------------------------------------------------------------------------- #
# Pin declaration
pinDir = 23
pinStep = 22
pinSwitch = 25
pinEnable = 24
# --------------------------------------------------------------------------- #

# --------------------------------------------------------------------------- #
# Global variables
micro_pausa = 0.0001
pasos_mm = 200   # 200 ESTO OBLIGA A QUE LA PRECISION SEA DE 1mm
MAX_HEIGHT = 280 # Altura maxima dependiendo de la estructura | run.py tambien tiene este valor. Validar que ambos sean iguales
# --------------------------------------------------------------------------- #

# --------------------------------------------------------------------------- #
# GPIO declaration
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
GPIO.setup(pinDir, GPIO.OUT)
GPIO.setup(pinStep, GPIO.OUT)
GPIO.setup(pinEnable, GPIO.OUT)
GPIO.setup(pinSwitch, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.output(pinEnable, True)#Desengancha el motor (False para enganchado, True para desenganchado
# --------------------------------------------------------------------------- #

# --------------------------------------------------------------------------- #


class Puente():
    def __init__(self, in_height=5):
        self.activo = False
        self.Primer_movimiento(in_height)
        self.height = in_height

    def set_altura(self, altura):
        if not self.activo:
            self.activo = True
            GPIO.output(pinEnable, False)                   #Engancha el motor
            GPIO.output(pinDir, True)                      #Indica giro horario (Bajar | False)
            while GPIO.input(pinSwitch):                    #Hasta que llegue al final de carrera
                GPIO.output(pinStep, True)                  #Da pulsos (pasos)
                time.sleep(micro_pausa)
                GPIO.output(pinStep, False)
                time.sleep(micro_pausa)
            GPIO.output(pinDir, False)                      #Indica giro antihorario (Subir | True)
            altura = MAX_HEIGHT if altura > MAX_HEIGHT else altura
            for _ in range(int(pasos_mm * altura)):      #Hasta llegar a la altura
                GPIO.output(pinStep, True)                  #Da pulsos (pasos)
                time.sleep(micro_pausa)
                GPIO.output(pinStep, False)
                time.sleep(micro_pausa)                  #Suma un paso
            GPIO.output(pinEnable, True)                    #Desengancha el motor
            self.activo = False
            return altura

    def move_up(self, npasos, pause = micro_pausa):
        GPIO.output(pinEnable, False)                   #Engancha el motor
        GPIO.output(pinDir, False)                      #Indica giro antihorario (subir) # 29/08/24
        for _ in range(npasos):      
            GPIO.output(pinStep, True)                  #Da pulsos (pasos)
            time.sleep(pause)
            GPIO.output(pinStep, False)
            time.sleep(pause)
        GPIO.output(pinEnable, True)                    #Desengancha el motor
        return True

    def move_down(self, npasos, pause = micro_pausa):
        GPIO.output(pinEnable, False)                   #Engancha el motor
        GPIO.output(pinDir, True)                      #Indica giro horario (bajar)
        for _ in range(npasos):
            if GPIO.input(pinSwitch):                   #Hasta llegar a la altura
                GPIO.output(pinStep, True)                  #Da pulsos (pasos)
                time.sleep(pause)
                GPIO.output(pinStep, False)
                time.sleep(pause)
            else:
                GPIO.output(pinEnable, True)
        return True

    def move_puente(self, new_height):
        if not self.activo:
            self.activo = True
            dh = max(min(new_height, MAX_HEIGHT), 0) - self.height
            npasos = int(abs(dh * pasos_mm))
            if npasos > 0:
                dh_true = npasos / pasos_mm
                if dh > 0:
                    new_height = self.height + dh_true
                    self.height = MAX_HEIGHT if new_height > MAX_HEIGHT else new_height
                    self.move_up(npasos)
                else:
                    new_height = self.height - dh_true
                    self.height = 0 if new_height < 0 else new_height
                    self.move_down(npasos)
                self.activo = False
                return True
            else:
                self.activo = False
                return False
        else:
            return False
        
    def Auto_movimiento(self,height):
        tt = Thread(target=self.move_puente, args=(height,))
        tt.start()

    def Primer_movimiento(self,height):
        tt = Thread(target=self.set_altura, args=(height,))
        tt.start()

    def Estado(self):
        if not self.activo:
            #pinEnable
            GPIO.output(pinEnable, False)#0
            if GPIO.input(pinEnable) == 1:
                return 0
            GPIO.output(pinEnable, True)
            if GPIO.input(pinEnable) == 0:
                return 0
            
            #pinStep
            GPIO.output(pinStep, False)#0
            if GPIO.input(pinStep) == 1:
                return 2
            GPIO.output(pinStep, True)
            if GPIO.input(pinStep) == 0:
                return 2
            
            #pinSwitch
            if GPIO.input(pinSwitch) == 0:
                return 2
            
            #pinDir
            GPIO.output(pinDir, False)#0
            if GPIO.input(pinDir) == 1:
                return 2
            GPIO.output(pinDir, True)
            if GPIO.input(pinDir) == 0:
                return 2
        return 0


"""# Exported functions
def set_altura_proceso(var):
    th = Thread(target=height_setup, args=(var,))
    th.start()

def set_altura(altura):
    GPIO.output(pinEnable, False)                   #Engancha el motor
    GPIO.output(pinDir, True)                      #Indica giro horario (Bajar | False)
    while GPIO.input(pinSwitch):                    #Hasta que llegue al final de carrera
        GPIO.output(pinStep, True)                  #Da pulsos (pasos)
        time.sleep(micro_pausa)
        GPIO.output(pinStep, False)
        time.sleep(micro_pausa)
    GPIO.output(pinDir, False)                      #Indica giro antihorario (Subir | True)
    altura = MAX_HEIGHT if altura > MAX_HEIGHT else altura
    for _ in range(int(pasos_mm * altura)):      #Hasta llegar a la altura
        GPIO.output(pinStep, True)                  #Da pulsos (pasos)
        time.sleep(micro_pausa)
        GPIO.output(pinStep, False)
        time.sleep(micro_pausa)                  #Suma un paso
    GPIO.output(pinEnable, True)                    #Desengancha el motor
    return True

def height_setup(height = MAX_HEIGHT):
    #move_down(MAX_HEIGHT)
    #move_up(height)
    set_altura(height)
    return height

# Cambio 29/08/24
def move_up(height = 5, pause = micro_pausa):
    if height > MAX_HEIGHT:
        return False
    # steptime_in = time.time()                     #Variable para medir el tiempo
    GPIO.output(pinEnable, False)                   #Engancha el motor
    GPIO.output(pinDir, False)                      #Indica giro antihorario (subir) # 29/08/24
    for _ in range(int(pasos_mm * height)):      
        GPIO.output(pinStep, True)                  #Da pulsos (pasos)
        time.sleep(pause)
        GPIO.output(pinStep, False)
        time.sleep(pause)

    GPIO.output(pinEnable, True)                    #Desengancha el motor
    print("Altura seteada.") 
    return True

def move_down(height = 5, pause = micro_pausa):
    GPIO.output(pinEnable, False)                   #Engancha el motor
    GPIO.output(pinDir, True)                      #Indica giro horario (bajar)
    for _ in range(int(pasos_mm * height)):
        if GPIO.input(pinSwitch):                   #Hasta llegar a la altura
            GPIO.output(pinStep, True)                  #Da pulsos (pasos)
            time.sleep(pause)
            GPIO.output(pinStep, False)
            time.sleep(pause)
        else:
            GPIO.output(pinEnable, True)
"""
