#ifndef __DELTA_LIBRARY_H_INCLUDED
#define __DELTA_LIBRARY_H_INCLUDED 
#include <ros/ros.h>
#include <iostream>
#include "modbus_tcp/modbus.h"
#include <boost/shared_ptr.hpp>
#include "delta_modbus/delta_infomation.h"
#include "delta_modbus/delta_exception.h"


DELTA_NAMESPACE_BEGIN
class PLC
{  
public:
    PLC(std::string ip_address, int port, int id = 1);

    virtual ~PLC();
    
    /**
     * @brief Connect to PLC
     */
    void connect(void);

     /**
     * @brief Close to PLC
     */
    void close(void);

     /**
     * @brief Checking PLC is connected
     */
    bool checkConnected(void);

    /**
     * @brief Write ON/OFF M Bit
     * @param M_number  M bit
     * @return 0/-1
     */
    int writeM(int M_number, const bool status);


    /** 
     * @brief Set ON/OFF multiple M bit
     * @param start_number  begin M bit
     * @param end_number    end M bit
     * @return 0/-1
     */
    int mulWriteM(int start_number, int end_number, bool *status);


    /** 
     * @brief SET ON M Bit
     * @param M_number  M bit
     * @return 0/-1
     */
    int setM(int M_number);

    /** 
     * @brief  SET OFF M Bit
     * @param M_number Node handle to get param for PLC
     * @return 0/-1
     */
    int resetM(int M_number);

    /** 
     * @brief Set ON multiple M bit
     * @param start_number  begin M bit
     * @param end_number    end M bit
     * @return 0/-1
     */
    int mulSetM(int start_number, int end_number);

    /** 
     * @brief Set OFF multiple M bit
     * @param start_number  begin M bit
     * @param end_number    end M bit
     * @return 0/-1
     */
    int mulResetM(int start_number, int end_number);

    /** 
     * @brief Get load M Bit
     * @param M_number  M bit 
     * @param buffer    Status of M bit
     * @return 0/-1
     */
    int getM(int M_number, bool &buffer);

    /** 
     * @brief Get load mul M bit 
     * @param start_number  Begin M bit
     * @param end_number    End M bit
     * @param buffer        Status of M bit  
     * @return 0/-1
     */
    int mulGetM(int start_number, int end_number, bool* buffer);

    /**
     * @brief Set On output Y
     * @param Y_number  
     * @return 0/-1
     */
    int setY(int Y_number);

    /** 
     * @brief Set Off output Y
     * @param Y_number  
     * @return 0/-1
     */
    int resetY(int Y_number);

    /** 
     * @brief Set multiple output Y is ON/OFF
     * @param start_number  begin M bit
     * @param end_number    end M bit
     * @return 0/-1
     */
    int mulWriteY(int start_number, int end_number, bool *buffer);

    /** 
     * @brief Set multiple output Y is ON
     * @param start_number  begin M bit
     * @param end_number    end M bit
     * @return 0/-1
     */
    int mulSetY(int start_number, int end_number);

    /** 
     * Set multiple output Y is OFF
     * @param start_number  begin M bit
     * @param end_number    end M bit
     * @return 0/-1
     */
    int mulResetY(int start_number, int end_number);
    
    /** 
     * @brief Get status Y coils from start_number to end_number.
     * @param start_number  begin M bit
     * @param end_number    end M bit
     * @param buffer        The status bit coils add to buffer
     */
    int mulGetY(int start_number, int end_number, bool *buffer);

    /** 
     * @brief Read D register
     * @param D_number Number D
     * @param buffer   Value of D_number
     */
    int getD(int D_number, uint16_t &buffer);

    /** 
     * @brief Send data to D register
     * @param D_number Number D
     * @param buffer   Value of D_number
     */
    int mulGetD(int start_number, int end_number, uint16_t *buffer);

    /** 
     * @brief Send data to D register ()
     * @param start_number  Begin D register
     * @param end_number    End D register
     * @param buffer        Buffer to store Data Read from Input Bits
     */
    int setD(int D_number, int16_t &buffer);

    /** 
     * @brief Send data to D register ()
     * @param start_number  Begin D register
     * @param end_number    End D register
     * @param buffer        Buffer to store Data Read from Input Bits
     */
    int mulSetD(int start_number, int end_number, uint16_t *buffer);
    
    /** 
     * @brief Read X bit
     * @param X_number  Number X
     * @param buffer    Status of X
     */
    int getX(int X_number, bool &buffer);

    /** 
     * @brief Read X bit
     * @param start_number  Begin number X
     * @param end_number    End number X
     * @param buffer        Status of X
     */
    int mulGetX(int start_number, int end_number, bool* buffer);

    /** 
     * @brief Read C register
     * @param C_number Number C
     * @param buffer   Value of C_number
     */
    int getC(int C_number, uint16_t &buffer);

    /** 
     * @brief Send data to C register ()
     * @param start_number  Begin C register
     * @param end_number    End C register
     * @param buffer        Buffer to store Data Read from Input Bits
     */
    int mulGetC(int start_number, int end_number, uint16_t *buffer);

    /**
     * @brief get error information
     */
    inline uint8_t getError();

private:
    /* Properties */
    uint8_t error_num;
    boost::shared_ptr<modbus> mb_;      
};
DELTA_NAMESPACE_END

#endif
