""" myRIO API: A RESTful API server for the myRIO

    Last update: 2024/03/14 Aitzol Ezeiza Ramos UPV/EHU

    This library uses Flask and Waitress to create an API
    based on myRIO_library. Not all the functions are
    served this way, but the basics are there:
        · Digital Inputs and Outputs
        · Analog Inputs and Outputs
        · onboard button and LEDs
        · onboard accelerometer
        - MXP board components
    The default port is 8080. Some examples of API calls
    (using curl) would be the following:

    curl -X POST http://172.22.11.2:8080/digital_output/2/1

    This turns on the digital output DIO2 on the default MXP port (A)
    If you use Windows Powershell, you should replace the -X with -method X

    curl -method POST http://172.22.11.2:8080/digital_output/2/1

    You can change the default port with a parameter:

    curl -X GET http://172.22.11.2:8080/digital_input/3?port=B

    Read the examples un the examples folder for more info.
    """


from flask import Flask, jsonify, request
import myRIO_base

DEFAULT_HTTP_PORT = 8080

app = Flask(__name__)

@app.before_first_request
def setup():
    """ We need to create a session before any API call
        We use a global handler for that.
    """
    global myrio_handler
    myrio_handler = myRIO_base.MyRIO()

@app.route('/digital_input/<int:channel_in>', methods=['GET'])
def get_digital_input(channel_in: int):
    """ Returns the value (true/false) of a digital input """
    port_in = request.args.get('port', default='A', type=str)
    value = myrio_handler.read_digital_input(channel=channel_in,port=port_in)
    return jsonify({'value': value})

@app.route('/digital_output/<int:channel_in>/<int:value_in>', methods=['POST'])
def set_digital_output(channel_in: int, value_in: int):
    """ Sets the value (true 1, false 0) of a digital output """
    port_in = request.args.get('port', default='A', type=str)
    myrio_handler.write_digital_output(channel=channel_in,
                                       port=port_in,
                                       value=bool(value_in))
    return jsonify({'success': True})

@app.route('/analog_input/<int:channel_in>', methods=['GET'])
def get_analog_input(channel_in: int):
    """ Returns the value (volts in float type) of an analog input """
    port_in = request.args.get('port', default='A', type=str)
    value = myrio_handler.read_analog_input(channel=channel_in,port=port_in)
    return jsonify({'value': value})

@app.route('/analog_output/<int:channel_in>/<float:value_in>', methods=['POST'])
def set_analog_output(channel_in: int, value_in: float):
    """ Sets the value (volts in float type) of an analog output """
    port_in = request.args.get('port', default='A', type=str)
    myrio_handler.write_analog_output(channel=channel_in, port=port_in, value=value_in)
    return jsonify({'success': True})

# Define routes for the onboard inputs and outputs
@app.route('/onboard_button', methods=['GET'])
def get_onboard_button():
    """ Returns the value (true/false) of the onboard button """
    value = myrio_handler.read_button()
    return jsonify({'value': value})

@app.route('/onboard_leds/<int:value_in>', methods=['POST'])
def set_onboard_leds(value_in: int):
    """ Sets the value (0..15 integer) of the onboard LEDs """
    myrio_handler.write_leds_integer(value_in)
    return jsonify({'success': True})

@app.route('/onboard_accelerometer', methods=['GET'])
def get_onboard_accelerometer():
    """ Returns the value (x, y, z floats) of the onboard accelerometer """
    values = myrio_handler.read_analog_accelerometer()
    response_data = {
        'x': values[0],
        'y': values[1],
        'z': values[2]
    }
    return jsonify(response_data)

# MXP board components: buttons, RGB LED, Temperature sensor, Light sensor

@app.route('/mxp_button/<int:button_in>', methods=['GET'])
def get_mxp_button(button_in: int):
    """ Returns the value (true/false) of one of the buttons.
        We expect 1 or 2, first (black) and second (white).
    """
    port_in = request.args.get('port', default='A', type=str)
    value = myrio_handler.read_MXP_button(button=button_in,port=port_in)
    return jsonify({'value': value})

@app.route('/mxp_rgb_color/<int:color_in>', methods=['POST'])
def set_mxp_rgb_color(color_in: int):
    """ Sets the color (0 to 7) of the MXP RGB LED
        Remember that the order is G(0)R(1)B(2)
        Green is 1, Red is 2, Blue is 4
        White is 7 and Off is 0.
    """
    port_in = request.args.get('port', default='A', type=str)
    myrio_handler.write_MXP_RGB_LED(color=color_in, port=port_in)
    return jsonify({'success': True})

@app.route('/mxp_temperature', methods=['GET'])
def get_mxp_temperature():
    """ Returns the temperature (degrees in float type) of
        the NTC temperature sensor (MXP board)
    """
    port_in = request.args.get('port', default='A', type=str)
    value = myrio_handler.read_MXP_temperature(port=port_in)
    return jsonify({'value': value})

@app.route('/mxp_luminosity', methods=['GET'])
def get_mxp_luminosity():
    """ Returns the luminosity (percentage in float type) of
        the LDR light sensor (MXP board)
    """
    port_in = request.args.get('port', default='A', type=str)
    value = myrio_handler.read_MXP_luminosity(port=port_in)
    return jsonify({'value': value})


if __name__ == '__main__':
    from waitress import serve
    serve(app, host='0.0.0.0', port=DEFAULT_HTTP_PORT)
    # 0.0.0.0 means it will be served in all network interfaces

    # Instead of serving, you can debug the application
    # using Flask's server
    # app.run(debug=True)
