
using namespace std;

class i2c
{
    public:
        i2c();
        void startupI2C();  // read I2C devices at startup
        void scanI2Cbus();  // scan I2C bus every 10 seconds for changes
    private:
        unsigned long long prevMillisScanI2C = 0;  // track when last scan happened
        short i2cID[15] = {};  //
        short i2cDriverID[15] = {};  // 
        short i2cDeviceTypeID[15] = {};  
        short i2cDecAddress[15] = {};
        // short i2cHexAddress[15] = {};
        short i2cEnabled[15] = {};
        short i2cTotalSaved = 0;  // track total i2c devices 
        short i2cTotalSavedPrev = 0;
        short i2cTotalProbes = 0;  // track how many probe circuits are connected
        short i2cTotalPca9685 = 0;  // track how many pca9685 circuits are connected
        char *filename = (char*)"/dev/i2c-1"; // Define the i2c file path
        int filePath; // open file for read and right
};
i2c::i2c(){}

void i2c::startupI2C() {  // read I2C devices at startup
    std::cout << " " << std::endl;
    std::cout << "startupI2C --------------------------------" << std::endl;
    MYSQL_RES *res;
    MYSQL_ROW row;

    i2cTotalProbes = 0;
    i2cTotalPca9685 = 0;
    // read all I2C devices stored in database
    connectMysql();
    // std::string query = "SELECT i2cID, i2cDeviceTypeID, decAddress, enabled FROM i2cDevices WHERE enabled = '1' ORDER BY decAddress ASC";  // construct query string
    std::string query = "SELECT i2cID, i2cDeviceTypeID, i2cDriverID, decAddress, enabled FROM i2cDevices ORDER BY decAddress ASC";  // construct query string
    mysql_query(conn, query.c_str());  // run query
    res = mysql_use_result(conn);
    
    while ((row = mysql_fetch_row(res)) != NULL)
    {
        i2cID[i2cTotalSaved] = atoi(row[0]);
        i2cDeviceTypeID[i2cTotalSaved] = atoi(row[1]);
        i2cDriverID[i2cTotalSaved] = atoi(row[2]);
        i2cDecAddress[i2cTotalSaved] = atoi(row[3]);
        i2cEnabled[i2cTotalSaved] = atoi(row[4]);
        if ((i2cDeviceTypeID[i2cTotalSaved] == 1) && (i2cEnabled[i2cTotalSaved] == 1)) {i2cTotalProbes++;}  // probe circuits
        else if ((i2cDeviceTypeID[i2cTotalSaved] == 2) && (i2cEnabled[i2cTotalSaved] == 1)) {  // pca9685 drivers
            pca9685.changePCA9685Address(i2cTotalPca9685, i2cDecAddress[i2cTotalSaved]);  // update pca9685.h with i2c address
            pca9685.changePCA9685DriverID(i2cTotalPca9685, i2cDriverID[i2cTotalSaved]);  // update pca9685.h with driverID
            // std::cout << "pca9685Address          = " << pca9685.getPCA9685Address(i2cTotalPca9685) << std::endl;
            i2cTotalPca9685++;
        }
        i2cTotalSaved++;
    }
    mysql_free_result(res);
    mysql_disconnect(); 

    std::cout << "i2cTotalProbes          = " << i2cTotalProbes << std::endl;
    std::cout << "i2cTotalPca9685         = " << i2cTotalPca9685 << std::endl;
    std::cout << "i2cTotalSaved           = " << i2cTotalSaved << std::endl;
    
    for(short a=0; a < i2cTotalSaved; a++ )  // go through all possible address on the bus
    {
        std::cout << "i2cID[a]            = " << i2cID[a] << std::endl;
        std::cout << "i2cDeviceTypeID[a]  = " << i2cDeviceTypeID[a] << std::endl;
        std::cout << "i2cDriverID[a]      = " << i2cDriverID[a] << std::endl;
        std::cout << "i2cDecAddress[a]    = " << i2cDecAddress[a] << std::endl;
        std::cout << "i2cEnabled[a]       = " << i2cEnabled[a] << std::endl;
        std::cout << "" <<  std::endl;
    }

    pca9685.changePCA9685totalEnabled(i2cTotalPca9685);  // update pca9685.h with total pca9685's enabled
    
    prevMillisScanI2C = 0;
        std::cout << "startupComplete           - " << startupComplete << std::endl;
    // scanI2Cbus();
	if (startupComplete == 0) {
        filePath = open(filename, O_RDWR); // open file for read and write
        // delay(1000);
        // scanI2Cbus();
    }
    
}

void i2c::scanI2Cbus() {  // scan I2C bus every 10 seconds for changes
        // std::cout << "startupComplete           - " << startupComplete << std::endl;
        // std::cout << "currentMillisTime         - " << currentMillisTime << std::endl;
        // std::cout << "prevMillisScanI2C + 10000 - " << prevMillisScanI2C + 10000 << std::endl;
        // prevMillisScanI2C = currentMillisTime;
        // std::cout << "prevMillisScanI2C + 10000 - " << prevMillisScanI2C + 10000 << std::endl;
    // if (currentMillisTime >= (prevMillisScanI2C + 10000))  // scan i2c bus every 10 seconds
    // {
        // prevMillisScanI2C = currentMillisTime;
        short totalScanned = 0;  // track how many i2c devices are scanned on the bus
        short decAddressScanned[15] = {};  // track decimal addresses of i2c devices seen on bus
        std::cout << "Scanning I2C BUS - " << std::endl;
        
        for(short a=1; a < 127; a++ )  // go through all possible address on the bus
        {
            if ((a == 104) || (a == 87)) {continue;} // if new i2c device is an rtc or rtc eeprom we can ignore it

            char inData[10];
            if (ioctl(filePath, I2C_SLAVE, a) < 0)  // check if we can access the i2c bus
            {
                std::cout << "Failed to acquire bus access." << std::endl;
                continue;
            }

            short length = 1;  // Number of bytes to read
            if (read(filePath, inData, 1) == length) {  // read one byte to see if address is on bus
                decAddressScanned[totalScanned] = a;  // record addresses that respond
                totalScanned++;
                std::cout << "Found I2C Address - " << a << std::endl;
            }
        }


        if (i2cTotalSavedPrev != totalScanned)  // check if number of scanned devices changed from last scan
        {
            // std::cout << "I2C DEVICES CHANGED SINCE LAST SCAN" << std::endl;
            short b = 0;  // used to scroll through addresses scanned on bus
            for(short a=0; a < i2cTotalSaved; a++ )  // go through all devices in database and update changes based on i2c bus
            {
                // std::cout << "saved  - " << i2cID[a] << ", " << i2cDeviceTypeID[a] << ", " << i2cDriverID[a] << ", " << i2cDecAddress[a] << ", " << i2cEnabled[a] << std::endl;
                if (i2cDecAddress[a] == decAddressScanned[b]) {b++;}  // address scanned is in database so we can check next
                // address in database wasn't scanned on bus so we will mark as unplugged 
                else if ((i2cDeviceTypeID[a] == 1) && (i2cEnabled[a] == 1)) {  // mark pH probe unplugged if not scanned
                    // std::cout << "mark pH unplugged        - " << i2cDecAddress[a] << std::endl;
                    connectMysql();
                    std::string query = "UPDATE probes SET plugged = '0' WHERE address = '" + to_string(i2cDecAddress[a]) + "'";
                    mysql_query(conn, query.c_str()); // run query
                    mysql_disconnect(); 
                }
                else if ((i2cDeviceTypeID[a] == 2) && (i2cEnabled[a] == 1)) {  // mark pca9685 unplugged if not scanned
                    // std::cout << "mark pca9685 unplugged   - " << i2cDecAddress[a] << std::endl;
                    i2cEnabled[a] = 0;  // mark variable to match database
                    
                    short count = pca9685.getPCA9685totalEnabled();
                    count--;
                    pca9685.changePCA9685totalEnabled(count);  // update pca9685.h with total pca9685's enabled

                    connectMysql();
                    std::string query = "UPDATE i2cDevices SET enabled = '0' WHERE decAddress = '" + to_string(i2cDecAddress[a]) + "'";
                    mysql_query(conn, query.c_str()); // run query
                    mysql_disconnect(); 
                }
            }


            // std::cout << "totalScanned           - " << totalScanned << std::endl;
            // std::cout << "i2cTotalSaved          - " << i2cTotalSaved << std::endl;

            short newDevicesSaved = 0;  // used to reload i2c variables if new device was found
            for(short a=0; a < totalScanned; a++ )  // go through all i2c devices scanned and check if it's already in database or new device
            {
                short f = 0;  // flag if already in database
                for(short b=0; b < i2cTotalSaved; b++ )  // go through all i2c devices in database
                {
                    if (decAddressScanned[a] == i2cDecAddress[b])  // check if scanned address is in database
                    {
                        // std::cout << "Address already saved  - " << decAddressScanned[a] << std::endl;
                        f = 1;  // set flag so we don't save
                        break;  // exit search for scanned address and go to next scanned address
                    }
                }
                if (f == 0)  // i2c device is new, add to database
                {
                    // std::cout << "saving to database     - " << decAddressScanned[a] << std::endl;
                    if ((decAddressScanned[a] == 104) || (decAddressScanned[a] == 87)) {} // if new i2c device is an rtc or rtc eeprom we can ignore it
                    else  // save everything else
                    {
                        connectMysql();
                        std::string query = "INSERT INTO i2cDevices (decAddress) VALUES('" + to_string(decAddressScanned[a]) + "')";
                        mysql_query(conn, query.c_str()); // run query
                        mysql_disconnect(); 
                    }
                    
                    // if (decAddressScanned[a] == 104)  // if new i2c device is an rtc with address 0x68 or 104
                    // {
                    //     // update record in i2cDevices table as dummy and disabled
                    //     query = "UPDATE i2cDevices\
                    //             SET i2cDriverID = '1',\
                    //                 new = '0'\
                    //                 enabled = '0'\
                    //             WHERE decAddress = '104'";
                    //     mysql_query(conn, query.c_str());  // run query
                    // }

                    // if (decAddressScanned[a] == 87)  // if new i2c device is an rtc eeprom with address 0x57 or 87
                    // {
                    //     // update record in i2cDevices table with RTC driverID and set new to no
                    //     query = "UPDATE i2cDevices\
                    //             SET i2cDriverID = '1',\
                    //                 new = '0',\
                    //                 enabled = '0'\
                    //             WHERE decAddress = '87'";
                    //     mysql_query(conn, query.c_str());  // run query
                    // }
                }
            }
        }

        i2cTotalSavedPrev = totalScanned;  // track how many devices were seen this scan
    // }
}

i2c i2c;