//=========================================================================
//  Copyright (c) Kitware, Inc.
//  All rights reserved.
//  See LICENSE.txt for details.
//
//  This software is distributed WITHOUT ANY WARRANTY; without even
//  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
//  PURPOSE.  See the above copyright notice for more information.
//=========================================================================
#include "smtk/session/rgg/json/jsonCore.h"
#include "smtk/session/rgg/json/jsonCoreExportParameters.h"

#include <iostream>

namespace smtk
{
namespace session
{
namespace rgg
{
using json = nlohmann::json;

void to_json(json& j, const Core& core)
{
  j["name"] = core.name();
  j["geomType"] = static_cast<int>(core.geomType());
  j["zOrigin"] = core.zOrigin();
  j["height"] = core.height();
  // Nlohmann would serialie the schema map as json array instead of json object.
  // So we manually seralize it here.
  const Core::UuidToSchema& layout = core.layout();
  json uuidToSchemaJson = json::object();
  for (const auto& uToS : layout)
  {
    uuidToSchemaJson[uToS.first.toString()] = uToS.second;
  }
  j["layout"] = uuidToSchemaJson;

  const Core::UuidToCoordinates& eTC = core.entityToCoordinates();
  json eTCJson = json::object();
  for (const auto& eTCIter : eTC)
  {
    eTCJson[eTCIter.first.toString()] = eTCIter.second;
  }
  j["entityToCoordinates"] = eTCJson;

  const Core::UuidToCoordinates& pdTC = core.pinsAndDuctsToCoordinates();
  json pdTCJson = json::object();
  for (const auto& pdTCIter : pdTC)
  {
    pdTCJson[pdTCIter.first.toString()] = pdTCIter.second;
  }
  j["pinsAndDuctsToCoordinates"] = pdTCJson;

  j["latticeSize"] = core.latticeSize();
  j["ductThickness"] = core.ductThickness();
  j["exportParameters"] = core.exportParams();
}

void from_json(const json& j, Core& core)
{
  try
  {
    core.setName(j.at("name"));
    core.setGeomType(j.at("geomType"));
    core.setZOrigin(j.at("zOrigin"));
    core.setHeight(j.at("height"));

    // Nlohmann cannot deserialize complicatd map properly.
    // So we manually deseralize it here.
    Core::UuidToSchema layout;
    json layoutJson = j.at("layout");
    for (const auto& iterL: layoutJson.items())
    {
      std::vector<std::pair<int, int>> schema = iterL.value();
      layout[iterL.key()] = schema;
    }

    Core::UuidToCoordinates entityToCoords;
    json eTCJson = j.at("entityToCoordinates");
    for (const auto& iterL: eTCJson.items())
    {
      std::vector<std::tuple<double, double, double>> coords = iterL.value();
      entityToCoords[iterL.key()] = coords;
    }
    core.setEntityToCoordinates(entityToCoords);

    Core::UuidToCoordinates pdToCoords;
    json pdTCJson = j.at("pinsAndDuctsToCoordinates");
    for (const auto& iterL: pdTCJson.items())
    {
      std::vector<std::tuple<double, double, double>> coords = iterL.value();
      pdToCoords[iterL.key()] = coords;
    }
    core.setPinsAndDuctsToCoordinates(pdToCoords);

    core.setLayout(layout);
    std::pair<int, int> ls = j.at("latticeSize");
    core.setLatticeSize(ls.first, ls.second);
    std::pair<double, double> thickness = j.at("ductThickness");
    core.setDuctThickness(thickness.first, thickness.second);

    CoreExportParameters ep = j.at("exportParameters");
    core.setExportParams(ep);
  }
  catch (json::exception& e)
  {
    std::cerr << e.what() << "\n";
    std::cerr << "RGG core does not have a valid json object" << std::endl;
    return;
  }
}

} // namespace rgg
} // namespace session
} // namespace smtk
