
using namespace std;

class update
{
    public:
        update();
        void checkForUpdate(short manual);  // check if there's an update available
        void checkIfUpdating();  // check at startup if program just updated
        void runUpdate();  // run update
        void updateFinished();  // update finished
        void userNotifiedUpdateComplete();  // user notified update complete 
        void updateAutoUpdate(short update);  // update auto update
        void updateUpdateAvailable(short update);  // update auto update
        short getUpdateAvailable();  // get updateAvailable status for frontend
        void v6_1();
        void v6_2();
        void v6_3();
        void v6_4();
        void v6_5();
        void v6_6();
    private:
        float appVersion = 0.0;
        float versionAvailable = 0.0;
        std::string versionAvailableS = "";
        short autoUpdate = 0;
        short updateAvailable = 0;
        short supportUpdate = 0;
};
update::update(){}

short update::getUpdateAvailable() {  // get updateAvailable status for frontend
    return updateAvailable;
}

static size_t getAppVersion(void *contents, size_t size, size_t nmemb, void *userp) {  // extract Robo-Tank app version from web page
    ((std::string*)userp)->append((char*)contents, size * nmemb);
    return size * nmemb;
}

void update::v6_1() {  // version 6.1 update - first step
    std::cout << "Updating database for v6_1" << std::endl;
    connectMysql();
    std::string query = "ALTER TABLE systemSettings ADD db9_1 tinyint(1) NOT NULL DEFAULT '0'";
    mysql_query(conn, query.c_str()); // run query

    query = "ALTER TABLE systemSettings ADD db9_2 tinyint(1) NOT NULL DEFAULT '0'";
    mysql_query(conn, query.c_str()); // run query
    
    query = "INSERT INTO pinsType (pinTypeID, pinTypeName, pinType) VALUES('14','Toggle Switch','1')";
    mysql_query(conn, query.c_str()); // run query


    query = "CREATE TABLE `version` (\
                `versionID` int(11) NOT NULL,\
                `version` float NOT NULL,\
                `versionDate` date NOT NULL\
            ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;";
    mysql_query(conn, query.c_str()); // run query

    query = "CREATE TABLE `versionInfo` (\
                `versionInfoID` int(11) NOT NULL,\
                `versionID` int(11) NOT NULL,\
                `versionTypeID` int(11) NOT NULL,\
                `change` text NOT NULL\
            ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;";
    mysql_query(conn, query.c_str()); // run query

    query = "CREATE TABLE `versionType` (\
                `versionTypeID` int(11) NOT NULL,\
                `versionType` varchar(50) NOT NULL\
            ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;";
    mysql_query(conn, query.c_str()); // run query


    query = "ALTER TABLE `version`\
            ADD PRIMARY KEY (`versionID`);";
    mysql_query(conn, query.c_str()); // run query

    query = "ALTER TABLE `version`\
            MODIFY `versionID` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=0;";
    mysql_query(conn, query.c_str()); // run query

    query = "ALTER TABLE `versionInfo`\
            ADD PRIMARY KEY (`versionInfoID`),\
            ADD KEY `versionID` (`versionID`),\
            ADD KEY `versionTypeID` (`versionTypeID`);";
    mysql_query(conn, query.c_str()); // run query

    query = "ALTER TABLE `versionInfo`\
            MODIFY `versionInfoID` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=0;";
    mysql_query(conn, query.c_str()); // run query

    query = "ALTER TABLE `versionType`\
            ADD PRIMARY KEY (`versionTypeID`);";
    mysql_query(conn, query.c_str()); // run query

    query = "ALTER TABLE `versionType`\
            MODIFY `versionTypeID` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=0;";
    mysql_query(conn, query.c_str()); // run query

    query = "ALTER TABLE `versionInfo`\
            ADD CONSTRAINT `versionInfo_ibfk_1` FOREIGN KEY (`versionID`) REFERENCES `version` (`versionID`) ON DELETE CASCADE ON UPDATE CASCADE,\
            ADD CONSTRAINT `versionInfo_ibfk_2` FOREIGN KEY (`versionTypeID`) REFERENCES `versionType` (`versionTypeID`) ON DELETE CASCADE ON UPDATE CASCADE;";
    mysql_query(conn, query.c_str()); // run query

    
    query = "INSERT INTO `versionType` (`versionTypeID`, `versionType`) VALUES \
    (1, 'Added'),\
    (2, 'Updated'),\
    (3, 'Fixed');";
    mysql_query(conn, query.c_str()); // run query

    query = "INSERT INTO `version` (`versionID`, `version`, `versionDate`) VALUES \
    (1, 6.1, '2021-10-14');";
    mysql_query(conn, query.c_str()); // run query

    query = "INSERT INTO `versionInfo` (`versionInfoID`, `versionID`, `versionTypeID`, `change`) VALUES \
        (1, 1, 2, 'Configure Ports - Added Robo-Tank extensions to DB9 accessory types'),\
        (2, 1, 2, 'Configure Ports - Added all pin functions to advanced tab'),\
        (3, 1, 3, 'Program - Sensors were being checked when disabled'),\
        (4, 1, 1, 'Added a toggle switch as a sensor type'),\
        (5, 1, 2, 'Dashboard - Added sensor status to info boxes'),\
        (6, 1, 3, 'Custom Rules - Off rules were not saved correctly');";
    mysql_query(conn, query.c_str()); // run query

    mysql_disconnect(); 
    std::cout << "Finished Updating database for v6_1" << std::endl;

}

void update::v6_2() {  // version 6.2 update - first step
    std::cout << "Updating database for v6_2" << std::endl;
    connectMysql();
    std::string query = "DROP TABLE lightModeDetails;";
    mysql_query(conn, query.c_str()); // run query
    
    query = "DROP TABLE lightModes;";
    mysql_query(conn, query.c_str()); // run query

    query = "CREATE TABLE `lightModes` (\
                `modeID` int(11) NOT NULL,\
                `pinID` int(11) NOT NULL,\
                `start` int(11) NOT NULL DEFAULT 86399,\
                `startLevel` int(11) NOT NULL DEFAULT 0,\
                `enabled` tinyint(4) NOT NULL DEFAULT 1\
                ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=COMPACT;";
    mysql_query(conn, query.c_str()); // run query

    query = "ALTER TABLE `lightModes`\
                ADD PRIMARY KEY (`modeID`),\
                ADD KEY `pinID` (`pinID`);";
    mysql_query(conn, query.c_str()); // run query

    query = "ALTER TABLE `lightModes`\
                MODIFY `modeID` int(11) NOT NULL AUTO_INCREMENT;";
    mysql_query(conn, query.c_str()); // run query

    query = "ALTER TABLE `lightModes`\
                ADD CONSTRAINT `lightModes_ibfk_1` FOREIGN KEY (`pinID`) REFERENCES `pinsAvailable` (`pinID`) ON DELETE CASCADE ON UPDATE CASCADE;";
    mysql_query(conn, query.c_str()); // run query

    query = "INSERT INTO `version` (`versionID`, `version`, `versionDate`) VALUES \
    (2, 6.2, '2021-12-18');";
    mysql_query(conn, query.c_str()); // run query

    query = "INSERT INTO `versionInfo` (`versionInfoID`, `versionID`, `versionTypeID`, `change`) VALUES \
                (8, 2, 3, 'Custom Rules - Added ability to disable/enable dosing pumps'),\
                (9, 2, 3, 'pH Calibration - Could not adjust 2nd point value'),\
                (10, 2, 2, 'Light Modes - Change how modes are created and work'),\
                (11, 2, 1, 'Added Auto Logout');";
    mysql_query(conn, query.c_str()); // run query

    mysql_disconnect(); 
    std::cout << "Finished Updating database for v6_2" << std::endl;

}

void update::v6_3() {  // version 6.3 update - first step
    std::cout << "Updating database for v6_3" << std::endl;
    connectMysql();
    std::string query = "INSERT INTO `version` (`versionID`, `version`, `versionDate`) VALUES \
    (3, 6.3, '2021-12-25');";
    mysql_query(conn, query.c_str()); // run query

    query = "INSERT INTO `versionInfo` (`versionInfoID`, `versionID`, `versionTypeID`, `change`) VALUES \
                (12, 3, 3, 'Could not access Advanced view on Configure Ports Page'),\
                (13, 3, 3, 'Could not disable schedules');";
    mysql_query(conn, query.c_str()); // run query

    mysql_disconnect(); 
    std::cout << "Finished Updating database for v6_3" << std::endl;

}

void update::v6_4() {  // version 6.4 update - first step
    std::cout << "Updating database for v6_4" << std::endl;

    // std::string comm = "sudo sed -i 's/dtoverlay=w1-gpio$/#dtoverlay=w1-gpio/g' /boot/config.txt &> /dev/null";
    std::string comm = "sudo sed -i 's/^dtoverlay=w1-gpio/#dtoverlay=w1-gpio/g' /boot/config.txt &> /dev/null";
    system(comm.c_str());

    // add possible GPIO pins to /boot/config.txt file so we can use 1wire bus
    // comm = "dtoverlay=w1-gpio,gpiopin=4\n#dtoverlay=w1-gpio,gpiopin=18\n#dtoverlay=w1-gpio,gpiopin=17\n#dtoverlay=w1-gpio,gpiopin=27\n#dtoverlay=w1-gpio,gpiopin=19\n#dtoverlay=w1-gpio,gpiopin=20\n#dtoverlay=w1-gpio,gpiopin=26\n#dtoverlay=w1-gpio,gpiopin=21";
    // string filename("/boot/config.txt");
    // fstream file;

    // file.open(filename, std::ios_base::app);
    // if (file.is_open()) {file.write(comm.data(), comm.size());}


    comm = "echo 'dtoverlay=w1-gpio,gpiopin=4' | sudo tee -a /boot/config.txt &> /dev/null";
    system(comm.c_str());

    comm = "echo '#dtoverlay=w1-gpio,gpiopin=18' | sudo tee -a /boot/config.txt &> /dev/null";
    system(comm.c_str());

    comm = "echo '#dtoverlay=w1-gpio,gpiopin=17' | sudo tee -a /boot/config.txt &> /dev/null";
    system(comm.c_str());

    comm = "echo '#dtoverlay=w1-gpio,gpiopin=27' | sudo tee -a /boot/config.txt &> /dev/null";
    system(comm.c_str());

    comm = "echo '#dtoverlay=w1-gpio,gpiopin=19' | sudo tee -a /boot/config.txt &> /dev/null";
    system(comm.c_str());

    comm = "echo '#dtoverlay=w1-gpio,gpiopin=20' | sudo tee -a /boot/config.txt &> /dev/null";
    system(comm.c_str());

    comm = "echo '#dtoverlay=w1-gpio,gpiopin=26' | sudo tee -a /boot/config.txt &> /dev/null";
    system(comm.c_str());

    comm = "echo '#dtoverlay=w1-gpio,gpiopin=21' | sudo tee -a /boot/config.txt &> /dev/null";
    system(comm.c_str());

    comm = "sudo mv /var/www/html/updates/startup /var/www/html/cpp/";  // delete update folder and contents
    system(comm.c_str());

    comm = "sudo chown pi:www-data /var/www/html/cpp/startup";
    system(comm.c_str());
        
    comm = "sudo chmod 755 /var/www/html/cpp/startup";
    system(comm.c_str());

    connectMysql();
    std::string query = "INSERT INTO `version` (`versionID`, `version`, `versionDate`) VALUES \
    (4, 6.4, '2022-3-17');";
    mysql_query(conn, query.c_str()); // run query

    query = "INSERT INTO `versionInfo` (`versionInfoID`, `versionID`, `versionTypeID`, `change`) VALUES \
                (14, 4, 3, 'DC Ports - When put in manual mode the red dot on icon would disappear after a page refresh although it still remained in manual mode');";
    mysql_query(conn, query.c_str()); // run query
    
    query = "INSERT INTO `versionInfo` (`versionInfoID`, `versionID`, `versionTypeID`, `change`) VALUES \
                (15, 4, 2, 'System - removed wiringPi library to control GPIOs, now reading/writing GPIOs using sysfs');";
    mysql_query(conn, query.c_str()); // run query
    
    query = "INSERT INTO `versionInfo` (`versionInfoID`, `versionID`, `versionTypeID`, `change`) VALUES \
                (16, 4, 2, 'Dashboard - changed bottom dock to snap to bottom of browser');";
    mysql_query(conn, query.c_str()); // run query
    
    query = "INSERT INTO `versionInfo` (`versionInfoID`, `versionID`, `versionTypeID`, `change`) VALUES \
                (17, 4, 1, 'System - Added v2 and v3 controller compatibility');";
    mysql_query(conn, query.c_str()); // run query
    
    query = "INSERT INTO `versionInfo` (`versionInfoID`, `versionID`, `versionTypeID`, `change`) VALUES \
                (18, 4, 1, 'AC Outlets - Added ability to Invert output logic');";
    mysql_query(conn, query.c_str()); // run query
    
    query = "INSERT INTO `versionInfo` (`versionInfoID`, `versionID`, `versionTypeID`, `change`) VALUES \
                (19, 4, 1, 'DC Ports - Added ability to Invert output logic');";
    mysql_query(conn, query.c_str()); // run query
    
    query = "INSERT INTO `versionInfo` (`versionInfoID`, `versionID`, `versionTypeID`, `change`) VALUES \
                (20, 4, 3, 'Setup Wizard - Fixed form to configure new pca9685');";
    mysql_query(conn, query.c_str()); // run query
    
    query = "INSERT INTO `versionInfo` (`versionInfoID`, `versionID`, `versionTypeID`, `change`) VALUES \
                (21, 4, 3, 'PCA9685 - Fixed bug that would not allowing more than 2 PCA9685 modules');";
    mysql_query(conn, query.c_str()); // run query
    
    query = "INSERT INTO `versionInfo` (`versionInfoID`, `versionID`, `versionTypeID`, `change`) VALUES \
                (22, 4, 1, 'RTC - Added support for DS1307 and DS3231 real time clocks');";
    mysql_query(conn, query.c_str()); // run query
    
    query = "INSERT INTO `versionInfo` (`versionInfoID`, `versionID`, `versionTypeID`, `change`) VALUES \
                (23, 4, 2, 'Interface - Date and time on webpage now gets updated from backend instead of using computer date and time');";
    mysql_query(conn, query.c_str()); // run query

    query = "INSERT INTO `versionInfo` (`versionInfoID`, `versionID`, `versionTypeID`, `change`) VALUES \
                (24, 4, 2, 'Startup Wizard - Fixed DS18B20 scan and added controller version option');";
    mysql_query(conn, query.c_str()); // run query

    query = "ALTER TABLE `systemSettings` ADD `controllerVersion` TINYINT(4) NOT NULL DEFAULT '0' AFTER `autoUpdate`;";
    mysql_query(conn, query.c_str()); // run query

    query = "ALTER TABLE `systemSettings` DROP INDEX `boardTypeID`;";
    mysql_query(conn, query.c_str()); // run query

    query = "ALTER TABLE `systemSettings` CHANGE `boardTypeID` `configView` TINYINT(4) NOT NULL DEFAULT '1' COMMENT 'Configure Ports View';";
    mysql_query(conn, query.c_str()); // run query

    query = "UPDATE `pinsAvailable` SET `assigned` = '0' WHERE `pinsAvailable`.`assigned` = 'No';";
    mysql_query(conn, query.c_str()); // run query

    query = "UPDATE `pinsAvailable` SET `assigned` = '1' WHERE `pinsAvailable`.`assigned` = 'Yes';";
    mysql_query(conn, query.c_str()); // run query

    query = "ALTER TABLE `pinsAvailable` CHANGE `assigned` `assigned` TINYINT(1) NOT NULL DEFAULT '0';";
    mysql_query(conn, query.c_str()); // run query

    query = "UPDATE `pinsAvailable` SET `pinTypeID` = '5', `name` = 'DS18B20', `portName` = 'DS18B20' WHERE `pinsAvailable`.`pinID` = 92;";
    mysql_query(conn, query.c_str()); // run query

    query = "UPDATE `pinsAvailable` SET `portName` = 'Internal Fan' WHERE `pinsAvailable`.`pinID` = 112;";
    mysql_query(conn, query.c_str()); // run query

    query = "ALTER TABLE `pinsAvailable` CHANGE `portName` `portName` VARCHAR(70) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT 'DO NOT EDIT';";
    mysql_query(conn, query.c_str()); // run query

    query = "ALTER TABLE `pinsAvailable` DROP `wiringpi`;";
    mysql_query(conn, query.c_str()); // run query

    query = "ALTER TABLE `ds18b20` CHANGE `min` `min` FLOAT NULL DEFAULT '0', CHANGE `max` `max` FLOAT NULL DEFAULT '0';";
    mysql_query(conn, query.c_str()); // run query

    query = "ALTER TABLE `drivers` DROP `driverTypeID`;";
    mysql_query(conn, query.c_str()); // run query

    query = "ALTER TABLE `i2cDevices` DROP `plugged`;";
    mysql_query(conn, query.c_str()); // run query

    query = "ALTER TABLE `i2cDevices` DROP `hexAddress`;";
    mysql_query(conn, query.c_str()); // run query

    query = "ALTER TABLE `i2cDevices` DROP `plugged_DEL`;";
    mysql_query(conn, query.c_str()); // run query

    query = "ALTER TABLE `systemSettings` CHANGE `timeFormat` `timeFormat` TINYINT(4) NOT NULL DEFAULT '1';";
    mysql_query(conn, query.c_str()); // run query

    query = "ALTER TABLE `systemSettings` CHANGE `db9_1` `db9_1` TINYINT(4) NOT NULL DEFAULT '0';";
    mysql_query(conn, query.c_str()); // run query

    query = "ALTER TABLE `systemSettings` CHANGE `db9_2` `db9_2` TINYINT(4) NOT NULL DEFAULT '0';";
    mysql_query(conn, query.c_str()); // run query

    mysql_disconnect(); 
    std::cout << "Finished Updating database for v6_4" << std::endl;
}

void update::v6_5() {  // version 6.5 update - first step
    std::cout << "Updating database for v6_5" << std::endl;
    
    connectMysql();
    std::string query = "INSERT INTO `version` (`versionID`, `version`, `versionDate`) VALUES \
    (5, 6.5, '2022-4-9');";
    mysql_query(conn, query.c_str()); // run query

    query = "INSERT INTO `versionInfo` (`versionInfoID`, `versionID`, `versionTypeID`, `change`) VALUES \
                (25, 5, 1, 'PCA9685 - Added verification, when pca9685 is updated it is immediately read to verify it updated correctly, if not it tries again');";
    mysql_query(conn, query.c_str()); // run query

    query = "INSERT INTO `versionInfo` (`versionInfoID`, `versionID`, `versionTypeID`, `change`) VALUES \
                (26, 5, 1, 'GPIO - Added verification, when GPIO is updated it is immediately read to verify it updated correctly, if not it tries again');";
    mysql_query(conn, query.c_str()); // run query

    query = "INSERT INTO `versionInfo` (`versionInfoID`, `versionID`, `versionTypeID`, `change`) VALUES \
                (27, 5, 3, 'Browser DateTime - Clock would not show 24 hour format after adding RTC');";
    mysql_query(conn, query.c_str()); // run query

    query = "INSERT INTO `versionInfo` (`versionInfoID`, `versionID`, `versionTypeID`, `change`) VALUES \
                (28, 5, 1, 'System Logs - Added logging system to record all actions');";
    mysql_query(conn, query.c_str()); // run query

    query = "INSERT INTO `versionInfo` (`versionInfoID`, `versionID`, `versionTypeID`, `change`) VALUES \
                (29, 5, 3, 'Schedules - Date added was saved wrong in database after RTC was added');";
    mysql_query(conn, query.c_str()); // run query

    query = "INSERT INTO `versionInfo` (`versionInfoID`, `versionID`, `versionTypeID`, `change`) VALUES \
                (30, 5, 3, 'I2C Scanner - Removed auto scanner as it is not required');";
    mysql_query(conn, query.c_str()); // run query

    query = "INSERT INTO `versionInfo` (`versionInfoID`, `versionID`, `versionTypeID`, `change`) VALUES \
                (31, 5, 3, 'Charts - pH chart table in database was not being updated');";
    mysql_query(conn, query.c_str()); // run query

    query = "INSERT INTO `versionInfo` (`versionInfoID`, `versionID`, `versionTypeID`, `change`) VALUES \
                (32, 5, 2, 'Charts - charts were still getting timestamp from internet time, changed to controller system time');";
    mysql_query(conn, query.c_str()); // run query

    query = "ALTER TABLE `schedules` DROP `end_DELETE`;";
    mysql_query(conn, query.c_str()); // run query
    
    query = "DROP TABLE `robotank`.`frontEndData`";
    mysql_query(conn, query.c_str()); // run query

    query = "DROP TABLE `robotank`.`dateTimeSync`";
    mysql_query(conn, query.c_str()); // run query

    query = "INSERT INTO `errorsSource` (`errorSourceID`, `source`) VALUES (3, 'PCA9685');";
    mysql_query(conn, query.c_str()); // run query

    query = "INSERT INTO `errorsSource` (`errorSourceID`, `source`) VALUES (4, 'GPIO');";
    mysql_query(conn, query.c_str()); // run query

    query = "CREATE TABLE `log` (\
            `logID` int(11) NOT NULL,\
            `logSourceID` int(11) NOT NULL,\
            `logTypeID` int(11) NOT NULL,\
            `logPinID` int(11) NOT NULL,\
            `logActionID` int(11) NOT NULL,\
            `logTime` bigint(20) DEFAULT NULL\
            ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;";
    mysql_query(conn, query.c_str()); // run query

    query = "CREATE TABLE `logAction` (\
            `logActionID` int(11) NOT NULL,\
            `logAction` varchar(20) NOT NULL\
            ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;";
    mysql_query(conn, query.c_str()); // run query

    query = "INSERT INTO `logAction` (`logActionID`, `logAction`) VALUES\
            (0, 'Turn Off'),\
            (1, 'Turn On'),\
            (2, 'Rebooted Controller');";
    mysql_query(conn, query.c_str()); // run query

    query = "CREATE TABLE `logSource` (\
            `logSourceID` int(11) NOT NULL,\
            `logSource` varchar(30) NOT NULL\
            ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;";
    mysql_query(conn, query.c_str()); // run query

    query = "INSERT INTO `logSource` (`logSourceID`, `logSource`) VALUES\
            (1, 'Manual'),\
            (2, 'Light Mode'),\
            (3, 'Schedule'),\
            (4, 'Custom Rule'),\
            (5, 'Entered Manual Mode'),\
            (6, 'Resume Auto Mode'),\
            (7, 'Smart Startup'),\
            (8, 'Changed Controller Version'),\
            (9, 'Enabled DS18B20 Port'),\
            (10, 'Disable DS18B20 Port');";
    mysql_query(conn, query.c_str()); // run query

    query = "CREATE TABLE `logType` (\
            `logTypeID` int(11) NOT NULL,\
            `logType` varchar(20) NOT NULL\
            ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;";
    mysql_query(conn, query.c_str()); // run query

    query = "INSERT INTO `logType` (`logTypeID`, `logType`) VALUES\
            (1, 'AC Outlet'),\
            (2, 'DC Port'),\
            (3, 'Dosing Pump'),\
            (4, 'Auto Feeder'),\
            (5, 'Light'),\
            (6, 'Sensor Port');";
    mysql_query(conn, query.c_str()); // run query
    
    query = "ALTER TABLE `log`\
            ADD PRIMARY KEY (`logID`),\
            ADD KEY `logSourceID` (`logSourceID`),\
            ADD KEY `logTypeID` (`logTypeID`),\
            ADD KEY `logPinID` (`logPinID`),\
            ADD KEY `logActionID` (`logActionID`);";
    mysql_query(conn, query.c_str()); // run query

    query = "ALTER TABLE `logAction`\
            ADD PRIMARY KEY (`logActionID`);";
    mysql_query(conn, query.c_str()); // run query

    query = "ALTER TABLE `logSource`\
            ADD PRIMARY KEY (`logSourceID`);";
    mysql_query(conn, query.c_str()); // run query

    query = "ALTER TABLE `logType`\
            ADD PRIMARY KEY (`logTypeID`);";
    mysql_query(conn, query.c_str()); // run query

    query = "ALTER TABLE `log`\
            MODIFY `logID` int(11) NOT NULL AUTO_INCREMENT;";
    mysql_query(conn, query.c_str()); // run query

    query = "ALTER TABLE `logAction`\
            MODIFY `logActionID` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=3;";
    mysql_query(conn, query.c_str()); // run query

    query = "ALTER TABLE `logSource`\
            MODIFY `logSourceID` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=11;";
    mysql_query(conn, query.c_str()); // run query

    query = "ALTER TABLE `logType`\
            MODIFY `logTypeID` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=7;";
    mysql_query(conn, query.c_str()); // run query

    query = "ALTER TABLE `log`\
            ADD CONSTRAINT `log_ibfk_1` FOREIGN KEY (`logSourceID`) REFERENCES `logSource` (`logSourceID`) ON DELETE CASCADE ON UPDATE CASCADE,\
            ADD CONSTRAINT `log_ibfk_2` FOREIGN KEY (`logTypeID`) REFERENCES `logType` (`logTypeID`) ON DELETE CASCADE ON UPDATE CASCADE,\
            ADD CONSTRAINT `log_ibfk_3` FOREIGN KEY (`logPinID`) REFERENCES `pinsAvailable` (`pinID`) ON DELETE NO ACTION ON UPDATE CASCADE,\
            ADD CONSTRAINT `log_ibfk_4` FOREIGN KEY (`logActionID`) REFERENCES `logAction` (`logActionID`) ON DELETE CASCADE ON UPDATE CASCADE;";
    mysql_query(conn, query.c_str()); // run query

    mysql_disconnect(); 
    std::cout << "Finished Updating database for v6_5" << std::endl;
}

void update::v6_6() {  // version 6.6 update - first step
    std::cout << "Updating database for v6_6" << std::endl;
    
    connectMysql();
    std::string query = "INSERT INTO `version` (`versionID`, `version`, `versionDate`) VALUES \
    (6, 6.6, '2023-2-3');";  // year-month-day
    mysql_query(conn, query.c_str()); // run query

    query = "INSERT INTO `versionInfo` (`versionInfoID`, `versionID`, `versionTypeID`, `change`) VALUES \
                (33, 6, 2, 'Schedules - Updated schedules table for user interface');";
    mysql_query(conn, query.c_str()); // run query

    query = "INSERT INTO `versionInfo` (`versionInfoID`, `versionID`, `versionTypeID`, `change`) VALUES \
                (34, 6, 3, 'Schedules - If schedule was disabled when schedule list was filtered it would not appear disabled in list, only visual error');";
    mysql_query(conn, query.c_str()); // run query

    query = "INSERT INTO `versionInfo` (`versionInfoID`, `versionID`, `versionTypeID`, `change`) VALUES \
                (35, 6, 2, 'Schedules - List of schedules is now updated after confirmation is received from backend, previously it waited 250ms before reloading table');";
    mysql_query(conn, query.c_str()); // run query

    query = "INSERT INTO `versionInfo` (`versionInfoID`, `versionID`, `versionTypeID`, `change`) VALUES \
                (36, 6, 2, 'Schedules - Removed Off option for dosing pumps when creating a schedule');";
    mysql_query(conn, query.c_str()); // run query

    query = "INSERT INTO `versionInfo` (`versionInfoID`, `versionID`, `versionTypeID`, `change`) VALUES \
                (37, 6, 3, 'Schedules - If schedule was created using Repeat Every 1 Day setting the first days schedule would not run');";
    mysql_query(conn, query.c_str()); // run query

    query = "INSERT INTO `versionInfo` (`versionInfoID`, `versionID`, `versionTypeID`, `change`) VALUES \
                (38, 6, 3, 'Schedules - It was possible to add a new schedule without any days selected');";
    mysql_query(conn, query.c_str()); // run query

    query = "INSERT INTO `versionInfo` (`versionInfoID`, `versionID`, `versionTypeID`, `change`) VALUES \
                (39, 6, 1, 'Schedules - Added validation when editing a schedule, was possible to crash program without this');";
    mysql_query(conn, query.c_str()); // run query

    query = "INSERT INTO `versionInfo` (`versionInfoID`, `versionID`, `versionTypeID`, `change`) VALUES \
                (40, 6, 3, 'Custom Rules - If custom rule was for a pH probe it failed to run or disply correctly in UI');";
    mysql_query(conn, query.c_str()); // run query

    query = "INSERT INTO `versionInfo` (`versionInfoID`, `versionID`, `versionTypeID`, `change`) VALUES \
                (41, 6, 3, 'Custom Rules - If custom rule was using a DS18B20 and it wasn't detected the custom rule could be triggered based on another DS18B20 value');";
    mysql_query(conn, query.c_str()); // run query

    query = "INSERT INTO `versionInfo` (`versionInfoID`, `versionID`, `versionTypeID`, `change`) VALUES \
                (42, 6, 2, 'System Logs - Added port custom name to source field');";
    mysql_query(conn, query.c_str()); // run query

    query = "INSERT INTO `versionInfo` (`versionInfoID`, `versionID`, `versionTypeID`, `change`) VALUES \
                (43, 6, 1, 'Version Logs - Added version log to system settings page');";
    mysql_query(conn, query.c_str()); // run query

    query = "INSERT INTO `versionInfo` (`versionInfoID`, `versionID`, `versionTypeID`, `change`) VALUES \
                (45, 6, 1, 'Dosing Pumps - User can now select how many mL's to dose manually');";
    mysql_query(conn, query.c_str()); // run query

    query = "INSERT INTO `versionInfo` (`versionInfoID`, `versionID`, `versionTypeID`, `change`) VALUES \
                (46, 6, 1, 'Dosing Pumps - Added ability to create a group of schedules');";
    mysql_query(conn, query.c_str()); // run query

    query = "INSERT INTO `versionInfo` (`versionInfoID`, `versionID`, `versionTypeID`, `change`) VALUES \
                (47, 6, 1, 'Dosing Pumps - User can select how many mL's are dosed for each schedule');";
    mysql_query(conn, query.c_str()); // run query

    query = "INSERT INTO `versionInfo` (`versionInfoID`, `versionID`, `versionTypeID`, `change`) VALUES \
                (48, 6, 1, 'Dosing Pumps - Added system for dosing pump stirrers');";
    mysql_query(conn, query.c_str()); // run query

    query = "INSERT INTO `versionInfo` (`versionInfoID`, `versionID`, `versionTypeID`, `change`) VALUES \
                (49, 6, 1, 'Dosing Pumps - Speed of dosing pump can now be adjusted during calibration');";
    mysql_query(conn, query.c_str()); // run query

    query = "INSERT INTO `versionInfo` (`versionInfoID`, `versionID`, `versionTypeID`, `change`) VALUES \
                (50, 6, 1, 'Dosing Pumps - User can opt out using the reservior feature, pump can still run if reservior is empty');";
    mysql_query(conn, query.c_str()); // run query

    query = "INSERT INTO `versionInfo` (`versionInfoID`, `versionID`, `versionTypeID`, `change`) VALUES \
                (51, 6, 1, 'Dosing Pumps - Added alert for low reservior, user can set the low limit in milliliters');";
    mysql_query(conn, query.c_str()); // run query

    query = "INSERT INTO `versionInfo` (`versionInfoID`, `versionID`, `versionTypeID`, `change`) VALUES \
                (52, 6, 2, 'Real Time Clock - Raspberry Pi is now managing the real time clock');";
    mysql_query(conn, query.c_str()); // run query

    query = "INSERT INTO `versionInfo` (`versionInfoID`, `versionID`, `versionTypeID`, `change`) VALUES \
                (53, 6, 3, 'Configure Ports - When saving settings from a DB9 it was likely the program would crash as it was repeating save 8 times');";
    mysql_query(conn, query.c_str()); // run query

    query = "INSERT INTO `versionInfo` (`versionInfoID`, `versionID`, `versionTypeID`, `change`) VALUES \
                (54, 6, 2, 'Custom Rules - Updated custom rules to allow user to specify how many milliliters to dose');";
    mysql_query(conn, query.c_str()); // run query
    
    query = "ALTER TABLE `dosingPumps` CHANGE `dosePumpRate` `dosePumpRate` INT(11) NOT NULL DEFAULT '600' COMMENT 'ms/ml';";
    mysql_query(conn, query.c_str()); // run query

    query = "ALTER TABLE `dosingPumps` ADD `disableRes` BOOLEAN NOT NULL DEFAULT FALSE COMMENT 'Reservoir Disabled ' AFTER `doseInterval`;";
    mysql_query(conn, query.c_str()); // run query

    query = "ALTER TABLE `dosingPumps` ADD `pumpSpeed` SMALLINT NOT NULL DEFAULT '4095' COMMENT 'PWM value' AFTER `disableRes`;";
    mysql_query(conn, query.c_str()); // run query

    query = "ALTER TABLE `dosingPumps` ADD `resAlert` BOOLEAN NOT NULL DEFAULT TRUE AFTER `pumpSpeed`;";
    mysql_query(conn, query.c_str()); // run query

    query = "ALTER TABLE `dosingPumps` ADD `resEmail` BOOLEAN NOT NULL DEFAULT FALSE AFTER `resAlert`;";
    mysql_query(conn, query.c_str()); // run query

    query = "ALTER TABLE `dosingPumps` ADD `resAlertML` MEDIUMINT NOT NULL DEFAULT '0' AFTER `resEmail`;";
    mysql_query(conn, query.c_str()); // run query

    query = "ALTER TABLE `dosingPumps` ADD `stirrerRuntime` MEDIUMINT NOT NULL DEFAULT '10' COMMENT 'seconds' AFTER `doseStirrer`;";
    mysql_query(conn, query.c_str()); // run query

    query = "ALTER TABLE `dosingPumps` ADD `settlingRuntime` MEDIUMINT NOT NULL DEFAULT '5' COMMENT 'seconds' AFTER `stirrerRuntime`;";
    mysql_query(conn, query.c_str()); // run query

    query = "ALTER TABLE `dosingPumps` ADD `stirrerSpeed` SMALLINT NOT NULL DEFAULT '4095' COMMENT 'pwm value' AFTER `settlingRuntime`;";
    mysql_query(conn, query.c_str()); // run query

    query = "ALTER TABLE `dosingPumps` ADD `doseStirrerID` INT NOT NULL AFTER `dosePinID`, ADD INDEX (`doseStirrerID`);";
    mysql_query(conn, query.c_str()); // run query

    query = "INSERT INTO `pinsType` (`pinTypeID`, `pinTypeName`, `pinType`) VALUES (15, 'Dosing Pump Stirrer', '0');";
    mysql_query(conn, query.c_str()); // run query

    query = "ALTER TABLE `log` ADD `note` VARCHAR(100) NOT NULL DEFAULT '' AFTER `logTime`;";
    mysql_query(conn, query.c_str()); // run query

    query = "CREATE TABLE `dosingSchedules` (\
                `doseSchID` int(11) NOT NULL,\
                `scheduleID` int(11) NOT NULL,\
                `mL` double NOT NULL\
                ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;";
    mysql_query(conn, query.c_str()); // run query

    query = "ALTER TABLE `dosingSchedules`\
                ADD PRIMARY KEY (`doseSchID`),\
                ADD KEY `scheduleID` (`scheduleID`);";
    mysql_query(conn, query.c_str()); // run query

    query = "ALTER TABLE `dosingSchedules`\
                MODIFY `doseSchID` int(11) NOT NULL AUTO_INCREMENT;";
    mysql_query(conn, query.c_str()); // run query

    query = "ALTER TABLE `dosingSchedules`\
                ADD CONSTRAINT `dosingSchedules_ibfk_1` FOREIGN KEY (`scheduleID`) REFERENCES `schedules` (`scheduleID`) ON DELETE CASCADE ON UPDATE CASCADE;";
    mysql_query(conn, query.c_str()); // run query

    query = "CREATE TABLE `robotank`.`stirrers` (\
                `stirrerID` INT NOT NULL AUTO_INCREMENT,\
                `stirrerPinID` INT NOT NULL,\
                PRIMARY KEY (`stirrerID`), INDEX (`stirrerPinID`)\
                ) ENGINE = InnoDB;";
    mysql_query(conn, query.c_str()); // run query

    query = "ALTER TABLE `stirrers`\
                MODIFY `stirrerID` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=1;";
    mysql_query(conn, query.c_str()); // run query

    query = "ALTER TABLE `stirrers`\
                ADD CONSTRAINT `stirrers_ibfk_1` FOREIGN KEY (`stirrerPinID`) REFERENCES `pinsAvailable` (`pinID`) ON DELETE CASCADE ON UPDATE CASCADE;";
    mysql_query(conn, query.c_str()); // run query
    
    query = "DELETE FROM i2cDevices WHERE decAddress = '104'";  // remove RTC
    mysql_query(conn, query.c_str());  // run query

    query = "DELETE FROM i2cDevices WHERE decAddress = '87'";  // remove RTC eeprom
    mysql_query(conn, query.c_str());  // run query

    query = "ALTER TABLE `schedules` DROP `end_DELETE`;";
    mysql_query(conn, query.c_str());  // run query

    query = "INSERT INTO `i2cDevices` (`i2cID`, `i2cDeviceTypeID`, `i2cDriverID`, `decAddress`, `enabled`, `new`, `running`) VALUES (NULL, '0', '1', '104', '0', '0', '1')";
    mysql_query(conn, query.c_str());  // run query

    query = "INSERT INTO `i2cDevices` (`i2cID`, `i2cDeviceTypeID`, `i2cDriverID`, `decAddress`, `enabled`, `new`, `running`) VALUES (NULL, '0', '1', '87', '0', '0', '1')";
    mysql_query(conn, query.c_str());  // run query

    query = "DELETE FROM `drivers` WHERE `drivers`.`driverID` = 4";
    mysql_query(conn, query.c_str());  // run query

    query = "ALTER TABLE `rulesEquipment` ADD `doseML` FLOAT NOT NULL DEFAULT '0' AFTER `equipIgnore`;";
    mysql_query(conn, query.c_str());  // run query

    mysql_disconnect(); 

    std::string comm = "sudo apt -y remove fake-hwclock"; // remove fake hardware clock
    system(comm.c_str());

    comm = "sudo update-rc.d -f fake-hwclock remove"; // remove fake hardware clock
    system(comm.c_str());

    // comment out file so DS1307 RTC can be used
    comm = "sudo sed -i 's+if\\ \\[ -e /run/systemd/system+#if\\ \\[ -e /run/systemd/system+g' /lib/udev/hwclock-set";
    system(comm.c_str());

    comm = "sudo sed -i '0,/    exit/{s/    exit/#    exit/}' /lib/udev/hwclock-set";
    system(comm.c_str());

    comm = "sudo sed -i '0,/fi/{s/fi/#fi/}' /lib/udev/hwclock-set";
    system(comm.c_str());

    // comm = "sudo sed -i 's/dtparam=i2c_arm_baudrate=10000$/dtparam=i2c_arm_baudrate=10000\ndtoverlay=i2c-rtc,ds1307/g' /boot/config.txt";
    // system(comm.c_str());

    comm = "sudo echo 'dtoverlay=i2c-rtc,ds1307' | sudo tee -a /boot/config.txt &> /dev/null";
    system(comm.c_str());


    // std::string comm = "date"; // 
    // system(comm.c_str());

    // comm = "sudo hwclock -w"; // 
    // system(comm.c_str());

    // std::string comm = "sudo modprobe rtc-ds1307";
    // system(comm.c_str());

    // comm = "sudo bash";
    // system(comm.c_str());

    // comm = "echo ds1307 0x68 > /sys/class/i2c-adapter/i2c-1/new_device";
    // system(comm.c_str());

    // comm = "exit";
    // system(comm.c_str());

    // comm = "sudo hwclock -w";
    // system(comm.c_str());

    // comm = "sudo bash";
    // system(comm.c_str());

    // comm = "echo 'rtc-ds1307' >> /etc/modules";
    // system(comm.c_str());

    // comm = "echo """;
    // system(comm.c_str());

    // comm = "echo ds1307 0x68 > /sys/class/i2c-adapter/i2c-1/new_device";
    // system(comm.c_str());

    // comm = "exit";
    // system(comm.c_str());

    // comm = "sudo hwclock -s";
    // system(comm.c_str());

    std::cout << "Finished Updating database for v6_6" << std::endl;
}


void update::checkIfUpdating() {  // check at startup if program just updated
    if (updateAvailable == 2) 
    {
        checkForUpdate(1);
        if (supportUpdate == 1) 
        {
            unsigned last = versionAvailableS.find_last_of("_");
            std::string ver = versionAvailableS.substr(last+1);

            try {versionAvailable = std::stof(ver);}  // latest version available
            catch(invalid_argument& e) {std::cout << "ERROR 101 --------------------- " << std::endl; return;}
              // latest version available
            versionAvailableS = ver;  // latest version available
        }

        float totalUpdates = std::round((versionAvailable - appVersion) * 10);  // total updates needing to be installed
        float updating = appVersion;  // currently updating version x.x
        
        std::stringstream file;  // construct file\folder name
        for(short a=0; a < totalUpdates; a++ )  // 
        {
            updating = updating + 0.1;  // increment to next update
            file << "v_" << std::fixed << std::setprecision(1) << updating;  // round to 1 decimal place
            std::cout << "file.str()    = " << file.str() << std::endl;

            // update database
            if (file.str() == "v_6.1") {v6_1();}  //
            else if (file.str() == "v_6.2") {v6_2();}  //
            else if (file.str() == "v_6.3") {v6_3();}  //
            else if (file.str() == "v_6.4") {v6_4();}  //
            else if (file.str() == "v_6.5") {v6_5();}  //
            else if (file.str() == "v_6.6") {v6_6();}  //
        }

        // connectMysql();
        // std::string query = "UPDATE systemSettings SET updateRan = '0' WHERE userID = 1";
        // mysql_query(conn, query.c_str()); // run query
        // mysql_disconnect();
        
        if (supportUpdate == 0)  // normal update
        {
            appVersion = versionAvailable;
            connectMysql();
            std::string query = "UPDATE systemSettings SET version = '" + versionAvailableS + "' WHERE userID = 1";
            mysql_query(conn, query.c_str()); // run query
            mysql_disconnect(); 
        }
        else if (supportUpdate == 1)  // support update
        {
            connectMysql();
            std::string query = "UPDATE systemSettings SET versionLatest = '" + to_string(appVersion) + "' WHERE userID = 1";
            mysql_query(conn, query.c_str()); // run query
            mysql_disconnect();
        }
        
        if (file.str() == "v_6.6")  // reboot pi as we setup RTC in v6.6
        {
            std::string comm = "sudo reboot";  // reboot pi
            system(comm.c_str());   
        }


        // updateAvailable = 3;  // tells front end update is done
    }
}

void update::updateFinished() {  // update finished
    // std::cout << "" << std::endl;
    // std::cout << "" << std::endl;
    // std::cout << "updateFinished --------------------------------- " << std::endl;
    // std::cout << "" << std::endl;
    // std::cout << "" << std::endl;

    updateAvailable = 3;
    // if (supportUpdate == 0)  // normal update
    // {
    //     appVersion = versionAvailable;
    //     connectMysql();
    //     std::string query = "UPDATE systemSettings SET version = '" + versionAvailableS + "' WHERE userID = 1";
    //     mysql_query(conn, query.c_str()); // run query
    //     mysql_disconnect(); 
    // }
}

void update::userNotifiedUpdateComplete() {  // user notified update complete 
    // std::cout << "" << std::endl;
    // std::cout << "" << std::endl;
    // std::cout << "userNotifiedUpdateComplete --------------------------------- " << std::endl;
    // std::cout << "" << std::endl;
    // std::cout << "" << std::endl;

    updateAvailable = 0;
    connectMysql();
    std::string query = "UPDATE systemSettings SET updateRan = '0' WHERE userID = 1";
    mysql_query(conn, query.c_str()); // run query
    mysql_disconnect();
    
    // if (supportUpdate == 1)  // support update
    // {
    //     connectMysql();
    //     std::string query = "UPDATE systemSettings SET versionLatest = '" + to_string(appVersion) + "' WHERE userID = 1";
    //     mysql_query(conn, query.c_str()); // run query
    //     mysql_disconnect();
    // }
}

void update::runUpdate() {  // run update
    if (updateAvailable == 1)
    {
        // std::cout << "Running Update --------------- " << std::endl;
        // std::cout << "supportUpdate    = " << supportUpdate << std::endl;
        if (supportUpdate == 0)  // normal update
        {
            checkForUpdate(1);  // check for any new updates before running
            delay(500);
        }
        
        float totalUpdates = std::round((versionAvailable - appVersion) * 10);  // total updates needing to be installed
        float updating = appVersion;  // currently updating version x.x

        // std::cout << "totalUpdates = " << totalUpdates << std::endl;

        for(short a=0; a < totalUpdates; a++ )  // download and extract all updates to be installed
        {
            updating = updating + 0.1;  // increment to next update
            std::stringstream file;  // construct file\folder name
            file << "v_" << std::fixed << std::setprecision(1) << updating;  // round to 1 decimal place
            // std::cout << "updating     = " << updating << std::endl;
            // std::cout << "file         = " << file.str() << std::endl;
            // std::cout << "" << std::endl;
            // std::string comm = "cat /proc/cpuinfo | grep Serial | cut -d ' ' -f 2"

            // std::string comm = "sudo rm -rf /var/www/html/updates/" + file.str() + " &> /dev/null";  // delete update folder and contents
            // system(comm.c_str());

            // comm = "sudo rm /var/www/html/updates/" + file.str() + ".zip &> /dev/null";  // delete update folder and contents
            // system(comm.c_str());

            std::string comm = "sudo wget -c https://app.robo-tank.ca/public/updates/" + file.str() + ".zip -P /var/www/html/updates/";  // download update
            system(comm.c_str());

            // comm = "sudo mkdir /var/www/html/updates/" + file.str() + " &> /dev/null";  // create new temporary folder for update
            // system(comm.c_str());

            comm = "sudo unzip -o /var/www/html/updates/" + file.str() + ".zip -d /var/www/html/updates/";  // unzip update
            system(comm.c_str());
        
            comm = "sudo cp -r /var/www/html/updates/" + file.str() + "/* /var/www/html/";  // copy update files
            system(comm.c_str());
            
            comm = "sudo chmod 755 /var/www/html/cpp/startup";
            system(comm.c_str());

            delay(500);

            std::cout << "file.str()    = " << file.str() << std::endl;
        }

        updating = appVersion;  // currently updating version x.x
        for(short a=0; a < totalUpdates; a++ )  // delete temporary files from updates
        {
            updating = updating + 0.1;  // increment to next update
            std::stringstream file;  // construct file\folder name
            file << "v_" << std::fixed << std::setprecision(1) << updating;  // round to 1 decimal place
            // std::cout << "updating     = " << updating << std::endl;
            // std::cout << "file         = " << file.str() << std::endl;
            // std::cout << "" << std::endl;

            std::string comm = "sudo rm -rf /var/www/html/updates/" + file.str() + " &> /dev/null";  // delete update folder and contents
            system(comm.c_str());

            comm = "sudo rm /var/www/html/updates/" + file.str() + ".zip &> /dev/null";  // delete update folder and contents
            system(comm.c_str());
            delay(500);
        }
        
        // std::cout << "" << std::endl;
        // std::cout << "" << std::endl;
        // std::cout << "Finished Update" << std::endl;
        // std::cout << "" << std::endl;
        // std::cout << "" << std::endl;

        delay(500);
        updateAvailable = 2;
        connectMysql();
        std::string query = "UPDATE systemSettings SET updateRan = '" + to_string(updateAvailable) + "' WHERE userID = 1";
        mysql_query(conn, query.c_str()); // run query
        mysql_disconnect();
        
        std::string comm = "sudo reboot";  // reboot pi
        system(comm.c_str());
        // sudo wget -c https://www.robo-tank.ca/app/updates/6_11.zip -P /var/www/html/updates/
        // sudo wget -c https://www.robo-tank.ca/app/updates/6_11.zip
        // sudo unzip reef-pi_install_files.zip
        // sudo bash install_reefpi.sh
        // sudo rm -rf 6.1

    }
}

void update::checkForUpdate(short manual) {  // check if there's an update available
    // std::cout << " " << std::endl;
    // std::cout << "checkForUpdate------------------------------" << std::endl;
    MYSQL_RES *res;
    MYSQL_ROW row;

    connectMysql();
    std::string query = "SELECT autoUpdate, version FROM systemSettings WHERE userID = 1";  //
    mysql_query(conn, query.c_str());  // run query

    res = mysql_use_result(conn);
    while ((row = mysql_fetch_row(res)) != NULL)
    {
        autoUpdate = atoi(row[0]);
        appVersion = atof(row[1]);
    }
    mysql_disconnect(); 
    mysql_free_result(res);
    // std::cout << "autoUpdate = " << autoUpdate << std::endl;

    if ((autoUpdate == 1) || (manual == 1))  // auto or manual
    {
        CURL *curl;
        curl = curl_easy_init();
        if(curl) 
        {
            versionAvailableS = "";
            curl_easy_setopt(curl, CURLOPT_URL, "https://app.robo-tank.ca/public/version.html");
            curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, getAppVersion);
            curl_easy_setopt(curl, CURLOPT_WRITEDATA, &versionAvailableS);

            try {
                curl_easy_perform(curl);

                try {versionAvailable = std::stof(versionAvailableS);}  // latest version available
                catch(invalid_argument& e) {std::cout << "No Update Available" << versionAvailableS << std::endl;}

                // std::cout << "" << std::endl;
                // std::cout << "" << std::endl;
                // std::cout << "Robo-Tank Version = " << appVersion << std::endl;
                // std::cout << "Robo-Tank Version Available = " << versionAvailable << std::endl;
                // std::cout << "Robo-Tank Version Available = " << versionAvailableS << std::endl;
                // std::cout << "" << std::endl;

                // std::string supportUpdate = versionAvailableS.at(0);
                unsigned support = versionAvailableS.find("s");
                if (support == 0) {supportUpdate = 1;}  // support update
                else {supportUpdate = 0;}  // normal update
                // std::cout << "support    = " << support << std::endl;
                if (updateAvailable <= 1)
                {
                    if (supportUpdate == 1)  // support update
                    {
                        unsigned first = versionAvailableS.find("_");
                        unsigned last = versionAvailableS.find_last_of("_");
                        std::string id = versionAvailableS.substr (first+1,last-(first+1));
                        // std::cout << id << std::endl;
                        if (supportID == std::stoi(id))  // check if update belongs to this controller
                        {
                            // std::cout << "ID Matched ------------------- " << std::endl;

                            unsigned last = versionAvailableS.find_last_of("_");
                            std::string ver = versionAvailableS.substr(last+1);

                            try {versionAvailable = std::stof(ver);}  // latest version available
                            catch(invalid_argument& e) {std::cout << "ERROR 101 --------------------- " << std::endl; return;}
                            
                              // latest version available
                            versionAvailableS = ver;  // latest version available
                            // std::cout << "Robo-Tank Version    = " << appVersion << std::endl;
                            // std::cout << "versionAvailableS    = " << versionAvailableS << std::endl;
                            // std::cout << "versionAvailable     = " << versionAvailable << std::endl;

                            updateAvailable = 1;

                            connectMysql();
                            std::string query = "UPDATE systemSettings SET versionLatest = '" + versionAvailableS + "' WHERE userID = 1";
                            mysql_query(conn, query.c_str()); // run query
                            mysql_disconnect();
                        }
                    }
                    else  // normal update
                    {
                        if (versionAvailable >= 6) {
                            if (versionAvailable != appVersion) {
                                // std::cout << "Update Available" << std::endl;
                                updateAvailable = 1;
                                connectMysql();
                                std::string query = "UPDATE systemSettings SET versionLatest = '" + versionAvailableS + "' WHERE userID = 1";
                                mysql_query(conn, query.c_str()); // run query
                                mysql_disconnect(); 
                            }
                            else {
                                // std::cout << "Up to Date" << std::endl;
                                updateAvailable = 0;
                            }
                        }
                    }
                    // std::cout << "" << std::endl;
                }
            }
            catch(bad_alloc& e)
            {
                cerr<<"Robo-Tank Update Failed: "<<e.what() << endl;
                while(1){
                    sleep(1);
                }
            }

            curl_easy_cleanup(curl);  // cleanup
        }
    }

    // std::cout << "----------------------------------------" << std::endl;
}

void update::updateAutoUpdate(short update) {  // update auto update
    // std::cout << "updateAutoUpdate = " << update << std::endl;
    autoUpdate = update;

    connectMysql();
    std::string query = "UPDATE systemSettings SET autoUpdate = '" + to_string(autoUpdate) + "' WHERE userID = 1";
    mysql_query(conn, query.c_str()); // run query
    mysql_disconnect();

    if (autoUpdate == 0) {checkForUpdate(1);}
}

void update::updateUpdateAvailable(short update) {  // update auto update
    updateAvailable = update;
    // std::cout << "updateAvailable START = " << updateAvailable << std::endl;
}

update update;