// https://programmersqtcpp.blogspot.com/2022/04/arduino-lcd-con-sprintf.html

#include <Wire.h>
//#include <U8glib.h>
//#include <IRremote.h>
//#include <IRremote.hpp>
//#include "RTClib.h"
//#include <U8x8lib.h>
#include <JC_Button.h>
#include "encoder.h"
#include <float.h>

uint8_t u8data[] = { 20, 50, 10 };

typedef struct K8data K8data;
struct K8data {
  uint8_t * const data;
  const uint8_t idx;
};

const K8data PROGMEM stp = {
    u8data, 2
};

#define     _S8_          0x00
#define     _S16_         0x01
#define     _S32_         0x03
#define     _FLOAT_       (0x07 | 0x08)
#define     _SIGN_        0x08


#define     DATAIS_INT16        0x03
#define     DATAAS_FLOAT        0x04
#define     PTRTO_FLASH         0x08
#define     DATAIS_READONLY     0x10

#define TYPE_SIZE(flag) (flag & 0x03) + 1;
#define IS_FLOAT(flag)  ((flag & 0x0f) == 0x0f)
#define IS_U32(flag)    ((flag & 0x03) == 0x03)
#define IS_I32(flag)    ((flag & 0x0b) == 0x0b) 


Button btnEncoder(7);
Encoder enc0;

GCounter<int16_t> acounter(-1000, -100, 100, 1);
GCounter<float> bcounter(-63, -63, 0, 0.5);

//U8X8_SSD1306_128X64_NONAME_HW_I2C oled(/* reset=*/U8X8_PIN_NONE);

/*void oledInit() {
    oled.setBusClock(400000);
    oled.begin();
    oled.setPowerSave(0);
}*/

void isrEnc() {
  
  enc0.isrEvent();
}

typedef struct DT {
  uint16_t type;
  uint16_t ptr;
};

void print_addr_of(const char *s, void *addr) {
  Serial.print(s);
  Serial.print("0x");
  Serial.println((uint16_t)addr, HEX);
}

class _float;
class _int8;

typedef union {
  float f;
  uint32_t u32;
} fu32_t;

/*const int KONST = 10;
const int KONST = 10;*/
/*int KONST;
int KONST = 10;*/


void setup() {
  Serial.begin(115200);
  pinMode(LED_BUILTIN, OUTPUT);
  btnEncoder.begin();
  enc0.begin(19, 18, isrEnc);
  int8_t var = 031;  // 25 decimale
  Serial.println(var);
  print_addr_of("&var: ", &var);
  DT wvar = { 1, &var };
  print_addr_of("wvar.ptr: ", wvar.ptr);
  // avendo soltanto l'indirizzo non posso risalire al tipo
  // di variabile. Allora creo un array di puntatori a DT
  DT *ptrToDT[10];
  memset(ptrToDT, 0, 10);
  ptrToDT[0] = &wvar;
  //Serial.println(ptrToDT[0]->ptr, HEX);
  // dal puntatore 21FA posso ricavare l'oggetto wvar
  /*int KONST;
  int KONST = 10;*/

  for (uint8_t i = 0; i < 10; i++) {
    
    if (ptrToDT[i]->ptr == (uint16_t)&var) {
      Serial.println("trovato");
      Serial.print("type: ");
      Serial.println(ptrToDT[i]->type);
      break;
    }
  }

  /*
  #define     _S8_          0x00
  #define     _S16_         0x01
  #define     _S32_         0x03
  #define     _SIGN_        0x04
  #define     _FLOAT_       0x08
  */
  uint8_t typeflag = _S32_;
  Serial.println(IS_U32(typeflag));
  /*size_t dtSize = (typeflag & 0x03) + 1;
  uint8_t type = (typeflag & 0x08) >> 3;
  Serial.println(typeflag);
  Serial.println("size:     type");
  Serial.print(dtSize);
  Serial.print("          ");
  Serial.println(type);
  //Serial.println((float)4294967015);
  // FLT_MAX = 92498331941291525,46931904868093278364381540222035916
  // if (number > 4294967040.0) return print ("ovf");  // constant determined empirically
  // if (number <-4294967040.0) return print ("ovf");  // constant determined empirically
  fu32_t fu32;
  fu32.f = FLT_MAX;
  uint32_t fmant = fu32.u32 & 0xFFC00000;
  Serial.println(fmant);
  // fmant = 2134900736
  uint16_t _exp = (fu32.u32 >> 23) & 0xff;
  Serial.println(_exp);
  // _exp = 254
  bool sign = (fu32.u32 >> 31);
  Serial.println(sign);
  // sign = 0
  Serial.println(fu32.u32, HEX);*/
 
  //oledInit();
  Serial.println(stp.data[stp.idx]);
  stp.data[stp.idx] = 20;
  Serial.println(stp.data[stp.idx]);
  Serial.println((uint16_t)&stp, HEX);

    
}

uint8_t state;

void loop() {
  
  btnEncoder.read();
  switch (state) {
    case 0:
      bcounter.setEncoder(&enc0);
      Serial.println("## Change bcounter ##");
      Serial.println(bcounter.value());
      state = 1;
    break;
    case 1:
      bcounter.run();
      if (bcounter.isChanged()) {
        auto v = bcounter.value();
        Serial.println(v);
      }
      if (btnEncoder.wasPressed()) 
        state = 2;
    break;
    case 2:
      acounter.setEncoder(&enc0);
      Serial.println("## Change acounter ##");
      Serial.println(acounter.value());
      state = 3;
    break;
    case 3:
      acounter.run();
      if (acounter.isChanged()) {
        auto v = acounter.value();
        Serial.println(v);
      }
      if (btnEncoder.wasPressed()) 
        state = 0;
    break;

  }
  
} // end void loop()