#System
import sys
import time

#BrainStem
import brainstem
from brainstem import _BS_C #Gives access to aProtocolDef.h constants. 
from brainstem.pd_channel_logger import PDChannelLogger
from brainstem.result import Result

#Basic error handling
def basic_error_handling(stem, error, error_string="", exit=False, exit_code=99):
    extracted_error = Result.UNKNOWN_ERROR

    #Pull out the error code if someone hands us a Result object.
    if isinstance(error, Result):
        extracted_error = error.error
    elif isinstance(error, int):
        extracted_error = error
    else:
        raise RuntimeError("Unhandled type: %s" % (type(error)))

    if extracted_error != Result.NO_ERROR:
        extracted_error_text = Result.getErrorText(extracted_error)
        extracted_error_description = Result.getErrorDescription(extracted_error)
        print("Error Occurred: %s(%d) - %s" % (extracted_error_text, extracted_error, extracted_error_description))

        if len(error_string):
            print(error_string)

        if Result.PERMISSION_ERROR == extracted_error:
            print("This error indicates the device does not have the required Software Features to executed this API.")
            print("If you have purchased these features already you might only need to update your devices firmware.")
            print("If you are still having issues please contact Acroname Support: support@acroname.com")

        elif Result.TIMEOUT == extracted_error or Result.CONNECTION_ERROR == extracted_error:
            print("Fatal Error: Lost connection to device. Exiting")
            sys.exit(33)

        if exit:
            print("Exiting from basic_error_handling - Exit code: %d" % (exit_code))
            sys.exit(exit_code)

    if Result.NO_ERROR == extracted_error:
        return False
    else:
        return True


#Create a stem from the base class Module. 
#When working from the base class it is good practice to ask the device
#if it capable of doing something before trying it.
def create_and_connect_stem(serial_number):
    stem = brainstem.module.Module(0)
    error = stem.discoverAndConnect(1, serial_number) #TODO: Get basic info and print it out. (sn, version etc). 
    basic_error_handling(stem, error, ("Exiting: Could not connect. Error %d - SN: 0x%08X" % (error, serial_number)), exit=True, exit_code=1) 

    #Create System Class object
    system = brainstem.entity.System(stem, 0)

    #---------------------------------------------------------------------
    #Check if the device supports system.getSerialNumber()
    result = stem.hasUEI(_BS_C.cmdSYSTEM, _BS_C.systemSerialNumber, 0, (_BS_C.ueiOPTION_GET))
    s = "Exiting: There is an error with this devices ability to get its serial number: %s" % (result)
    basic_error_handling(stem, result, s, exit=True, exit_code=1) 

    sn_result = system.getSerialNumber()
    basic_error_handling(stem, sn_result, "system.getSerialNumber()", exit=True, exit_code=1) 
    #---------------------------------------------------------------------

    #---------------------------------------------------------------------
    #Check if the device supports system.getVersion()
    result = stem.hasUEI(_BS_C.cmdSYSTEM, _BS_C.systemVersion, 0, (_BS_C.ueiOPTION_GET))
    s = "Exiting: There is an error with this devices ability to get its firmware version: %s" % (result)
    basic_error_handling(stem, result, s, exit=True, exit_code=1) 

    version_result = system.getVersion()
    basic_error_handling(stem, version_result, "system.getVersion()", exit=True, exit_code=1) 
    #---------------------------------------------------------------------

    print("")
    print("Connected to device: 0x%08X" % (sn_result.value))
    print("Firmware Version: %s" % (brainstem.version.get_version_string(version_result.value)))
    print("Software Version: %s" % (brainstem.version.get_version_string()))
    print("")

    return stem


#Convenience function for creating a PDChannelLogger
def create_logger(stem, port_index):
    logger = PDChannelLogger(stem, port_index) #Create Logger object for given port
    error = logger.setEnabled(True) #Enable logging
    basic_error_handling(stem, error, "logger.setEnabled()", exit=True, exit_code=4)
    time.sleep(.1) #Allow the logger to get up and running.
    return logger


