#include <stdio.h>
#include "PM8000_Modbus_Map.h"
#include <cstring>
#include <time.h>
#include <stdlib.h>


uint16_t stub_readInputRegisters(uint16_t pFrom,  uint16_t pFor) {

    return pFrom - pFor;
}

uint16_t stub_getResponseBuffer(uint16_t pPos) {
  
    int r =(rand() % 65535); 
    return r;
}

typedef union {
    struct {
        uint16_t year : 7;
        uint16_t reserved1 : 9;
        uint16_t day : 5;
        uint16_t weekday : 3;
        uint16_t month : 4;
        uint16_t reserved2 : 4;
        uint16_t minutes : 6;
        uint16_t reserved3 : 1;
        uint16_t time_sync_quality : 1;
        uint16_t hour : 5;
        uint16_t reserved4 : 2;
        uint16_t daylight_savings : 1;
        uint16_t milliseconds : 16;
    };
    uint16_t words[4]; // Each word corresponds to the structure as 16-bit values
} DateTime;


void datetime_to_iso_string(DateTime dt,char *buffer,size_t buffer_size) {
    int full_year = 2000 + dt.year;
    int day = dt.day == 0 ? 1 : dt.day;
    int month = dt.month == 0 ? 1 : dt.month;
    int hour = dt.hour;
    int minute = dt.minutes;
    int seconds = dt.milliseconds / 1000;
    int milliseconds = dt.milliseconds % 1000;

    // Create the ISO 8601 formatted string
    snprintf(buffer, buffer_size, "%04d-%02d-%02dT%02d:%02d:%02d.%03d", 
             full_year, month, day, hour, minute, seconds, milliseconds);
}

void uint16_to_binary_string(uint16_t value, char *buffer) {
    for (int i = 15; i >= 0; i--) {
        buffer[15 - i] = (value & (1 << i)) ? '1' : '0';
    }
    buffer[16] = '\0'; 
}

uint32_t getRegisterUInt32(uint16_t highWord, uint16_t lowWord) {
    uint32_t val = (highWord << 16) +  lowWord;
    return val;
} 

int32_t getRegisterInt32(uint16_t highWord, uint16_t lowWord) {
    int32_t val = (highWord << 16) +  lowWord;
    return val;
} 

int64_t getRegisterInt64(uint16_t word1, uint16_t word2, uint16_t word3, uint16_t word4) {
    uint64_t val = ((uint64_t)word1 << 48) + ((uint64_t)word2 << 32) + (word3 << 16)  + word4;
    return val;
} 

float getRegisterFloat(uint16_t highWord, uint16_t lowWord) {
    uint32_t floatRaw = ((uint32_t)highWord << 16) | lowWord; 
    float floatValue;
    
    memcpy(&floatValue, &floatRaw, sizeof(float));
    return floatValue;
} 


// Main function: entry point for execution
int main() {
    srand(time(NULL)); 
    printf("Some testing function so that I can check the output of the register data loop\n");

    int lastreg = 0;
    for (int i  = 0; i < 1000; i++) {
        PM8000RegType creg = nextPM8000Reg(lastreg);
        lastreg = creg.address;
   
        //printf("LP: %d LastAddress: %d Address %d Name: %s\n",i, lastreg, creg.address, creg.name);

        if (strcmp(creg.type,"FLOAT32") == 0) {
            float floatValue = getRegisterFloat(stub_getResponseBuffer(0),stub_getResponseBuffer(1));
            printf("Float value: %f\n", floatValue);
        } else if (strcmp(creg.type,"INT16U") == 0) {
            uint16_t val = stub_getResponseBuffer(0);
            printf("Int value: %d\n", val);
        } else if (strcmp(creg.type,"INT32") == 0) {
            int32_t val =getRegisterInt32( stub_getResponseBuffer(0), stub_getResponseBuffer(1));
            printf("Int32 value: %d\n", val);
        } else if (strcmp(creg.type,"INT32U") == 0) {
            uint32_t val = getRegisterUInt32( stub_getResponseBuffer(0), stub_getResponseBuffer(1));
            printf("INT32U value: %d\n", val);
            
        } else if (strcmp(creg.type,"INT64") == 0) {
            int64_t val = getRegisterInt64(stub_getResponseBuffer(0), stub_getResponseBuffer(1), stub_getResponseBuffer(2), stub_getResponseBuffer(3));

            printf("Int64 value: %ld\n", val);
        }  else if (strcmp(creg.type,"UTF8") == 0) {
            char str[creg.size] = "";
            for (uint16_t j = 0; j < creg.size; j++) {
                uint8_t v = stub_getResponseBuffer(j);
                str[j] = v;
            }

            printf("String value: %s\n", str);
        }  else if (strcmp(creg.type,"DATETIME") == 0) {
            DateTime dt;
            dt.words[0] = stub_getResponseBuffer(0);
            dt.words[1] = stub_getResponseBuffer(2);
            dt.words[2] = stub_getResponseBuffer(3);
            dt.words[3] = stub_getResponseBuffer(4);

            char str[30] = "";
            datetime_to_iso_string(dt, str,30);
            printf("ISO 8601 Date-Time: %s\n", str);
        }  else if (strcmp(creg.type,"BITMAP") == 0) {
   
            char binary_string[17];
            char binary_string2[17];
            uint16_to_binary_string(stub_getResponseBuffer(0),binary_string);
            uint16_to_binary_string(stub_getResponseBuffer(1),binary_string2);
            printf("Bitmaps : %s  %s\n", binary_string,binary_string2);
        } else {
            printf("Not handled: %s\n", creg.type);
        }
   
    }

    printf("\n...");

    return 0;
}

