#pragma once

#include <iostream>
#include <array>
#include <string>
#include <optional>
#include <cmath>

#include <iomanip>

#include <wiringPi.h>
#include <wiringPiSPI.h>

using namespace std;

/**
Type: DT50-N2113
**/
class Sick_front{
    /**
     * @brief  Channel on which is ADC for front distance sensor connected
     */
    bool channel;

    /**
     * @brief WiringPi GPIO number of pin which start conversion by change 0->1
     */
    const int GPIO_conversion_start = 5;

    /**
     * @brief WiringPi GPIO number of pin which turn ON/OFF laser of sensor
     */
    const int GPIO_laser_enable = 4;

        /**
     * @brief   Minimal configured distance of sensor
     */
    const int range_min = 200;

    /**
     * @brief   Maximal configured distance of sensor
     */
    const int range_max = 10000;

    /**
     * @brief   Value of sense resistor in ohms used for current loop
     */
    const int sense_resistor = 150;

    /**
     * @brief   Current coresponding to minimal distance, configured in "range_min"
     */
    const float current_loop_min = 0.004;

    /**
     * @brief   Current coresponding to maximal distance, configured in "range_max"
     */
    const float current_loop_max = 0.020;

    /**
     * @brief   Current coresponding to state when minimal distance is exceeded
     */
    const float current_loop_close = 0.0035;

    /**
     * @brief   Current coresponding to state when maximal distance is exceeded
     */
    const float current_loop_far = 0.0205;

    /**
     * @brief   Voltage coresponding to maximal distance
     */
    const float voltage_max = current_loop_max*sense_resistor;

    /**
     * @brief   Voltage coresponding to minimal distance
     */
    const float voltage_min = current_loop_min*sense_resistor;

    /**
     * @brief   Voltage coresponding to state when maximal distance is exceeded
     */
    const float voltage_close = current_loop_close*sense_resistor;

    /**
     * @brief   Voltage coresponding to state when minimal distance is exceeded
     */
    const float voltage_far = current_loop_far*sense_resistor;

    /**
     * @brief  Reference voltage of ADC
     */
    const float reference_voltage = 3.308f;

public:
    /**
     * @brief   Construct a new Sick_front object
     *          Configure GPIO and SPI interface
     *
     * @param channel   Channel on which is sensor connected
     */
    Sick_front(bool channel = 1);

    /**
     * @brief Calculate distance measurted by distance sensor
     *
     * @return optional<unsigned int>   True and value in mm if in range, False otherwise
     */
    optional<unsigned int> Distance();

    /**
     * @brief Average multiple measurements of distance sensor output
     *
     * @param measurement_count         Amount of measurents to average
     * @return optional<unsigned int>   Same as Distance()
     */
    optional<unsigned int> Distance_avg(unsigned int measurement_count = 8);

    /**
     * @brief           Turn ON or OFF laser of sensor
     *
     * @param state     New state of laser
     */
    void Laser(bool state);

private:
    /**
     * @brief           Read raw ADC data from ADC
     *
     * @return uint16_t raw ADc data in 2's complement format
     */
    uint16_t Conversion_raw();

};
