#ifndef SERIALPORT_H
#define SERIALPORT_H

#include <string>
#include <termios.h>
//#include <windows.h>
#include <sys/types.h>


namespace Comms {

class SerialPort {
public:
    /** The constructor
     * @param path serial port path
     * @param speed the speed at which the port will be connected.
     * This value is taken from termios.h e.g. B576000 << Needs to be improved in future
     */
    SerialPort(std::string path, speed_t speed);

    /** Destructor */
    ~SerialPort();

    /** Opens the port, and sets the communication link parameters
     * @returns false if it cannot open the port
     */
    bool openPort();

    /** Closes the port */
    void closePort();

    /**
     * Return the port being opened
     */
    std::string getPort();

    /**
     * Changes the value of RTS line
     * @param state true will set it to high. False will set it to low
     */
    void setRTS(bool state);

    /**
     * Changes the value of DTR line
     * @param state true will set it to high. False will set it to low
     */
    void setDTR(bool state);

    /** Reads data from the serial port
     * @param buffer the buffer which will hold the data
     * @param size number of bytes that needs to be read
     * @param sec a positive integer value representing number of seconds to wait for data to become available.
     * @param usec a positive integer value representing number of micro seconds to wait for data to become available.
     * @returns the number of bytes actually read. Retuns -1 if it times out, -2 on any other error.
     */
    ssize_t readData(void* buffer, size_t size, unsigned int sec = 1,
            unsigned int usec = 0);

    /** Check for number of bytes available at the port. It uses the select statement
     * @param sec positive integer. Number of seconds to wait for data to become available.
     * @param usec positive integer. Number of micor seconds to wait for data to become available.
     * @returns Number of bytes available at the port. It it times out it will return -1. -2 for
     *          other errors.
     */
    ssize_t dataAvailable(unsigned int sec = 1, unsigned int usec = 0);

    /** Check for number of bytes available at the port. It uses the select statement.
     * The method waits indifinitely until there is data on the port
     * @param sec positive integer. Number of seconds to wait for data to become available.
     * @param usec positive integer. Number of micor seconds to wait for data to become available.
     * @returns Number of bytes available at the port. Returns -2 for errors.
     */
    ssize_t dataAvailableBlocking();

    /** Reads data from the serial port. It will block until data becomes available
     * @param buffer the buffer which will hold the data
     * @param size number of bytes that needs to be read
     * @returns the number of bytes actually read. Returns negative integer if there is an error
     */
    ssize_t readDataBlocking(void* buffer, size_t size);

    /** Makes multiple attempts to read N bytes of data from the port
     * @param buffer storage for the data to be read
     * @param nBytes number of bytes to be read
     * @param sec number of seconds to wait for data to become available
     * @param usec number of micro seconds to wait for the data to appear on the port.
     * @returns true if it can read all of the data requested
     */
    ssize_t nReadData(unsigned char* buffer, size_t nBytes,
            unsigned int sec = 1, unsigned int usec = 0);

    /** Sends data over the serial port
     * @param data pointer to the data
     * @param size the number of bytes to be sent
     */
    ssize_t sendData(const void *data, size_t size);

    /** Flush the Input buffer of the port */
    void flushInput(void);

private:
    int _fd;
    std::string _path;
    speed_t _speed;
    struct termios port_options_atStart;
};

}
#endif // SERIALPORT_H
