#!/usr/bin/python3

import sys
import time
import socket
sys.path.insert(0, "..")

from opcua import Client
from opcua import ua
from numpy import uint32

# definition of function to execute commands via OPC UA
def executeCommand(cmd):
    while outBusyBitNode.get_value():                               # wait for busy bit = false
        time.sleep(0.001)

    inCommandNoNode.set_value(cmd, ua.VariantType.Int32)            # set Trigger 

    while not outBusyBitNode.get_value():                           # wait for busy bit = true
        time.sleep(0.001)
    inCommandNoNode.set_value(0, ua.VariantType.Int32)              # reset trigger
                    
    while outBusyBitNode.get_value():                               # wait for busy bit = false
        time.sleep(0.001)

        
if __name__ == "__main__":

    # Connection to Camera via OPC-UA
    client = Client("opc.tcp://192.168.0.50:4840")      # connect using an IP Adress

    # Socket Connection
    HOST = "0.0.0.0"                                    # IP HORST 
    PORT = 3000                                         # Port HORST 

    try:        
        # connect to camera via OPC-UA
        print("connect to camera")
        client.connect()

        # connect to horstFX va Socket
        s = socket.socket()                             # Erstelle Socket Objekt
        s.bind((HOST, PORT))                            # Binde Port
        print("socket listen for client")
        s.listen(5)                                     # Warte auf client connection
        c, addr = s.accept()                            # Stelle Verbidnung mit client her
        print("socket accepted by client")
         
        doStop = False

        # get Objects node, this is where we should put our nodes
        root = client.get_root_node()

        # populating address space
        outBusyBitNode = root.get_child(["0:Objects", "2:Outputs", "2:BusyBit"])
        outResultNoNode = root.get_child(["0:Objects", "2:Outputs", "2:ResultNo"])
        outResultsNode = root.get_child(["0:Objects", "2:Outputs", "2:Results.50"])
        outErrorNoNode = root.get_child(["0:Objects", "2:Outputs", "2:ErrorNo"])

        inCameraNameNode = root.get_child(["0:Objects", "2:Inputs", "2:CameraName"])
        inRotationModeNode = root.get_child(["0:Objects", "2:Inputs", "2:RotationMode"])
        inCommandNoNode = root.get_child(["0:Objects", "2:Inputs", "2:CommandNo"])
        inConfigNameNode = root.get_child(["0:Objects", "2:Inputs", "2:ConfigName"])
        inSTLNameNode = root.get_child(["0:Objects", "2:Inputs", "2:STLName"])


        # open camera
        print("open camera")
        cameraName = "204929"                           # name of the camera
        inCameraNameNode.set_value(cameraName)          # set camaera name 
        executeCommand(6)                               # call execute function to execute the command

        if outErrorNoNode.get_value() == 0:
            print("connected to camera")
            c.sendall("Verbindung zur Kamera erfolgreich".encode('utf-8'))

        else :
            print("connection to camera could not be established")
            c.sendall("Es konnte keine Verindung zur Kamera hergestellt werden".encode('utf-8'))
                        
        # Wann ist Kamera vollständig geöffnet? Gibt es ein Kammando dazu von der Kamera?
        #time.sleep(8)
        
        # load camera configuration
        configName = c.recv(1024).decode()              # Lese HORST Nachricht über Socket
        print("load configuration:", configName);
        inConfigNameNode.set_value(configName)          # set config file name
        executeCommand(1)                               # call execute function to execute the command

        if outErrorNoNode.get_value() == 0:
            print("configuration has been loaded")
            c.sendall("Konfiguration erfolgreich geladen".encode('utf-8'))

        else :
            print("configuration could not be loaded")
            c.sendall("Fehler beim Laden der Konfiguration".encode('utf-8'))

        #time.sleep(5)
        
        inRotationModeNode.set_value("sxyz")            # set Rotation Mode
        
        while (not doStop):

            try:
                msg = c.recv(1024)                      # Lese HORST Nachricht über Socket

#************************************************************************************************trigger camera*******************************************************************************************
                
                if msg == b'Trigger':                   # check message of HORST

                    executeCommand(4)                   # call execute function to execute the command


#******************************************************************************'***************get camera results****************************************************************************************'
                        
                    # print("Error Number: ", outErrorNoNode.get_value())
                    
                    if outErrorNoNode.get_value() == 0:                                         # check camera for errors

                        print("Result Number: ", outResultNoNode.get_value())               

                        if outResultNoNode.get_value() != 0:                                    # check if camera has detected objects
                      
                            #cam_values_str = str(outResultsNode.get_value())
                            
                            cam_values = outResultsNode.get_value()
                            
                            # sort the detected objects regarding the object score
                            cam_values.sort(key=lambda x: float(x[0]), reverse=True)
                            print("Camera Object Values:\n", cam_values)

                            cam_values_str = str(cam_values)
                            c.sendall(cam_values_str.encode('utf-8'))                           # send complete camera value message
                            
                            #c.sendall(str(outResultsNode.get_value()[0][0]).encode('utf-8'))   # send just one camera value

                        else:
                            c.sendall("Kein Objekt gefunden".encode('utf-8'))
                    else :
                        c.sendall("Fehler".encode('utf-8'))

                        if outErrorNoNode.get_value() == 1:
                            ErrorMsg = "Unbekannter Systemfehler"

                        elif outErrorNoNode.get_value() == 2:
                            ErrorMsg = "Kamera kann nicht geoeffnet werden"
                            
                        elif outErrorNoNode.get_value() == 3:
                            ErrorMsg = "Keine Stereokamera angeschlossen"

                        elif outErrorNoNode.get_value() == 4:
                            ErrorMsg = "Kamera-Fehler"

                        elif outErrorNoNode.get_value() == 5:
                            ErrorMsg = "Suche fehlgeschlagen"

                        elif outErrorNoNode.get_value() == 6:
                            ErrorMsg = "Suche hat keine zuegehoeriges Modell"
                            
                        elif outErrorNoNode.get_value() == 7:
                            ErrorMsg = "Modell generieren fehlgeschlagen"

                        elif outErrorNoNode.get_value() == 8:
                            ErrorMsg = "3D-Referenzpunkt setzen fehlgeschlagen"

                        elif outErrorNoNode.get_value() == 9:
                            ErrorMsg = "Konfiguration konnte nicht geladen werden"

                        elif outErrorNoNode.get_value() == 10:
                            ErrorMsg = "Konfiguration konnte nicht gespeichert werden"
                            
                        elif outErrorNoNode.get_value() == 11:
                            ErrorMsg = "Befehl nicht implementiert"

                        elif outErrorNoNode.get_value() == 12:
                            ErrorMsg = "Falscher Index zum Abrufen der Ergebnisse"

                        elif outErrorNoNode.get_value() == 13:
                            ErrorMsg = "STL-Datei nicht gefunden"

                        c.sendall(ErrorMsg.encode('utf-8'))
                          
                else:
                    print("Program interrupted by HORST")
                    doStop = True

            except KeyboardInterrupt:
                print("Unterbrochen!")
                doStop = True
        
    finally:
        client.disconnect()
        c.close()


