#include "SHData.h"
#include <iostream>
#include <sstream>
#include <fstream>
#include "vtkForCenos/Interpolator.h"
#include "misc/miscFunctions.hpp"
#include "cenos_exception.h"

SHData::SHData()
{

}

SHData::~SHData()
{

}

SHData::SHData(std::string filename)
{
    if (!misc::fileExist(filename))
        return;

    ryml::Tree tree = misc::parseYaml(filename);

    if (tree["Time"] == nullptr)
    {
        throw cenos_exception("Internal error: Data required for steel phase calculation not found");
    }

    tree["Domain"] >> domain_name;
    tree["Time"] >> time;
    if (tree["NodeNr"] != nullptr)
    {
        tree["NodeNr"] >> node_nr;
        tree["NodeX"] >> node_x;
        tree["NodeY"] >> node_y;
        tree["NodeZ"] >> node_z;
    }

    if (tree["NodeMaxTemperature"] != nullptr)
        tree["NodeMaxTemperature"] >> node_maxTemp;

}

SHData& SHData::operator= (const SHData& that)
{
    // do the copy
    domain_name = that.domain_name;
    time = that.time;
    node_nr = that.node_nr;
    node_x = that.node_x;
    node_y = that.node_y;
    node_z = that.node_z;
    node_maxTemp = that.node_maxTemp;

    return *this;
}

void SHData::addNodes(std::vector< std::shared_ptr<Node >> nodes, double newtime)
{
    // do interpolation if does not match!
    std::vector<int> new_node_nr;
    std::vector<double> new_node_x;
    std::vector<double> new_node_y;
    std::vector<double> new_node_z;

    for (auto nd : nodes)
    {
        new_node_nr.push_back(nd->getId());
        new_node_x.push_back(nd->x());
        new_node_y.push_back(nd->y());
        new_node_z.push_back(nd->z());

    }

    if (newtime - time < 0)
    {

        //do the assignement, SHData does not match this calculation and will not be used
        node_nr = new_node_nr;
        node_x = new_node_x;
        node_y = new_node_y;
        node_z = new_node_z;
        node_maxTemp = {};
    }
    else
    {
        //do the interpolation if needed, SHData is from previous time step

        // is this check enough? Maybe compare coordinates?
        //std::cout << "node_nr " << node_nr.size() << " new_node_nr " << new_node_nr.size() << std::endl;
        //if (node_nr == new_node_nr)
        //    return;

        std::vector<std::vector<double>> old_points;
        for (int i = 0; i < node_x.size(); i++)
            old_points.push_back({ node_x[i], node_y[i], node_z[i] });

        std::vector<std::vector<double>> new_points;
        for (int i = 0; i < new_node_x.size(); i++)
            new_points.push_back({ new_node_x[i], new_node_y[i], new_node_z[i] });


        if (!node_maxTemp.empty())
        {
            Interpolator nodemaxTemp_interpolator;
            nodemaxTemp_interpolator.setOldPoints(old_points);
            nodemaxTemp_interpolator.setNewPoints(new_points);
            nodemaxTemp_interpolator.setOldData(node_maxTemp);
            node_maxTemp = nodemaxTemp_interpolator.getInterpolatedData();
        }


        node_nr = new_node_nr;
        node_x = new_node_x;
        node_y = new_node_y;
        node_z = new_node_z;
    }
}


void SHData::writeData(std::string filename)
{
    ryml::Tree tree;
    ryml::NodeRef r = tree.rootref();
    r |= ryml::MAP;
    r["Domain"] << domain_name.c_str();
    r["Time"] << time;
    r["NodeNr"] << node_nr;
    r["NodeX"] << node_x;
    r["NodeY"] << node_y;
    r["NodeZ"] << node_z;
    r["NodeMaxTemperature"] << node_maxTemp;

    FILE* yaml_file;

    char buffer[100];

    yaml_file = fopen(filename.c_str(), "w");

    if (yaml_file == NULL)
    {
        std::string message = "Error opening " + filename + " file";
        throw cenos_exception(message);
    }

    emit(tree, yaml_file);


    fclose(yaml_file);
}


std::string SHData::getDomainName()
{
    return domain_name;
}

double SHData::getTime()
{
    return time;
}

std::vector<double> SHData::getNodeMaxTemperature()
{
    return node_maxTemp;
}

std::vector<int> SHData::getNodeNr()
{
    return node_nr;
}

void SHData::setNodeMaxTemperature(std::vector<double> n_maxT)
{
    node_maxTemp = n_maxT;
}

void SHData::setTime(double t)
{
    time = t;
}

void SHData::setName(std::string n)
{
    domain_name = n;
}

