#ifndef _MCP4725_HPP_
#define _MCP4725_HPP_
#include <stdint.h>
#include <unistd.h>
#include <functional>
#include "../../interfaces/i2c.hpp"

template <typename T>
class MCP4725
{
	public:
		//typedef std::function<void(uint8_t,uint8_t*,uint8_t)> i2c_write_n_t;
		//typedef std::function<void(const uint8_t&,const uint8_t*,const uint8_t&)> i2c_write_n_t;
		//typedef void(*i2c_write_n_t)(const uint8_t&, const uint8_t*, const uint8_t&);
	
		//typedef std::function<void(int)>i2c_write_n_t;
		// address list
		enum i2c_addr
		{
			addr_0x60 = 0b01100000,
			addr_0x61 = addr_0x60 + 1,
			addr_0x62 = addr_0x60 + 2,
			addr_0x63 = addr_0x60 + 3,
			addr_0x64 = addr_0x60 + 4,
			addr_0x65 = addr_0x60 + 5,
			addr_0x66 = addr_0x60 + 6,
			addr_0x67 = addr_0x60 + 7
		};

		// power down impedance  modes
		enum pwrd_md
		{
			normal = 0x04,
			ohm_1k = 0x01,
			ohm_100k = 0x02,
			ohm_500k = 0x03
		};

		//using std::functional<uint8_t(uint8_t, uint8_t)> i2c_read_n_t;
		//using i2c_write_n_t = std::functional<void(uint8_t, uint8_t*,uint8_t)>;
		
		/**
		 * @brief Constructor of mcp4725 dac
		 * 
		 * @param power_down_mode pwrd_md power down mode
		 * @param address i2c_addr i2c address of the dac
		 * @param i2c_write i2c_write_n_t callback for i2c writ
		 */

		MCP4725(I2C<T>& i2c) :
            power_down_mode(pwrd_md::normal),
			address(addr_0x60),
			i2c(i2c),
			dac_value(0),
			eeprom_value(0)
        {
            uint8_t temp[3];
            this->dac_value = dac_value;
            
            temp[0] = cmd_write_dac | (power_down_mode << 1);
            temp[1] = static_cast<uint8_t>(dac_value >> 4);
            temp[2] = static_cast<uint8_t>(dac_value << 4);


            i2c.writeBuffer(address, temp, 3);
        }

	//	~MCP4725();
	


		void operator=(uint16_t dac_value)
        {
            uint8_t temp[3];
            this->dac_value = dac_value;
            
            temp[0] = cmd_write_dac | (power_down_mode << 1);
            temp[1] = static_cast<uint8_t>(dac_value >> 4);
            temp[2] = static_cast<uint8_t>(dac_value << 4);

            i2c.writeBuffer(address, temp, 3);
        }

		void operator==(uint16_t dac_and_eeprom_value)
        {
            uint8_t temp[6];
            dac_value = dac_and_eeprom_value;
            eeprom_value = dac_value;

            temp[0] = cmd_write_dac_and_eeprom | (power_down_mode << 1); 
            temp[1] = static_cast<uint8_t>(dac_and_eeprom_value >> 4);
            temp[2] = static_cast<uint8_t>(dac_and_eeprom_value << 4);
            temp[3] = temp[0];
            temp[4] = temp[1];
            temp[5] = temp[2];
            
            i2c.writeBuffer(address, temp, 6);
        }

		//void set_power
		

	private:

		enum commands_t
		{
			cmd_fast_mode = 0x00,
			cmd_write_dac = 0x40,
			cmd_write_dac_and_eeprom = 0x60
		};

		I2C<T>& i2c;

		i2c_addr address;
		pwrd_md power_down_mode;
		uint16_t dac_value;
		uint16_t eeprom_value;

};

#endif // _MCP4725_HPP_