/**************************************************
Includes
**************************************************/
#pragma once
#include <stdlib.h>
#include "Arduino.h"

/**************************************************
Definitions
**************************************************/
using namespace std;

/**************************************************
Class definition
**************************************************/
template <typename Elementtype>
class DataContainer
{
private:
    Elementtype **datalist;
    int maxsize;
    std::size_t currentsize; // How much data is saved in datalist

public:
    DataContainer(int maxcapacity);
    ~DataContainer();

    void init_data_saving();
    void add_data(Elementtype &new_Element, const int typenmbr);
    void end_data_saving();

    Elementtype *operator[](int posnumber) const;
    const std::size_t get_currentsize() const;

    Elementtype **get_all_data() const;
    void reset_all_data();
};

/*-------------------------------------------------------------------------------------------------------------------*/

/* Constructor for new Datacontainer with total capacity of maxsize */
template <typename Elementtype>
DataContainer<Elementtype>::DataContainer(int new_maxsize) : maxsize(new_maxsize), currentsize(0)
{
    maxsize = MAX_CONTAINER_SIZE / SPIRU_SENSOR;

    datalist = new Elementtype *[maxsize];
    for (int i = 0; i < maxsize; i++) // Declare a memory block of size maxsize
    {
        datalist[i] = new Elementtype[SPIRU_SENSOR]; // SUPERSPIRU/SMARTSPIRU?
    }
};

/* Deletes all <Element> individually */
template <typename Elementtype>
DataContainer<Elementtype>::~DataContainer()
{
    for (int i = 0; i < currentsize; i++)
    {
        if (datalist[i])
            delete datalist[i];
    }
    delete datalist;
}

/*call this before you want to add a new datastack*/
/*checks for saving space. If full: shifts all data to the left*/
template <typename Elementtype>
void DataContainer<Elementtype>::init_data_saving()
{
    if (maxsize == currentsize)
    {
        currentsize--;
        for (int i = 0; i < currentsize; i++)
        {
            for (int n = 0; n < SPIRU_SENSOR; n++)
            {
                datalist[i][n] = datalist[i + 1][n];
            }
        }
    }
};

/*adds a new <Element> to typenumber*/
/*SMART sensor enum: 0: Photodiode, 1: Temperature */
/*SUPER sensor enum: 0: Photodiode, 1: Temperature, 2: pH , 3: EC , 4: DO  */
template <typename Elementtype>
void DataContainer<Elementtype>::add_data(Elementtype &new_Element, const int Sensortype)
{
    datalist[currentsize][Sensortype] = new_Element;
};

/*call this when datastack is complete to update currentsize*/
template <typename Elementtype>
void DataContainer<Elementtype>::end_data_saving()
{
    currentsize++;
};

/*returns all Data*/
template <typename Elementtype>
Elementtype **DataContainer<Elementtype>::get_all_data() const
{
    return datalist;
};

/*returns size of contentlist*/
template <typename Elementtype>
const std::size_t DataContainer<Elementtype>::get_currentsize() const
{
    return currentsize;
};

/*returns <Element>* on posnumber in contentlist !! */
template <typename Elementtype>
Elementtype *DataContainer<Elementtype>::operator[](int posnumber) const
{
    return datalist[posnumber];
};

/* Deletes all Data of Datacontainer and allocates new memory*/
template <typename Elementtype>
void DataContainer<Elementtype>::reset_all_data()
{
    Serial.print("Start reset - currentsize:");
    Serial.println(currentsize);
    for (int i = 0; i < currentsize; i++)
    {
        if (datalist[i])
            Serial.println("Deleting");
            Serial.println(heap_caps_check_integrity_all(true));
            delete datalist[i];
            Serial.println(heap_caps_check_integrity_all(true));
    }
    // heap_caps_print_heap_info(MALLOC_CAP_DEFAULT);
    
    delay(2000);
    Serial.println("Second delete");
    delete datalist;

    datalist = new Elementtype *[maxsize];
    for (int i = 0; i < maxsize; i++) // Declare a memory block of size maxsize
    {
        datalist[i] = new Elementtype[SPIRU_SENSOR];
    }

    currentsize = 0;
}
