//=============================================================================
// 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/qt/rggNucCore.h"
#include "smtk/session/rgg/qt/qtLattice.h"

#include "smtk/io/Logger.h"
#include "smtk/model/AuxiliaryGeometry.h"
#include "smtk/model/Group.h"
#include "smtk/model/Resource.h"
#include "smtk/session/rgg/Assembly.h"
#include "smtk/session/rgg/Core.h"

#include "smtk/session/rgg/json/jsonCore.h"


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

rggNucCore::rggNucCore(smtk::model::EntityRef entity)
  : rggLatticeContainer(entity)
{
  m_resource = entity.resource();
  this->resetBySMTKCore(entity);
}

rggNucCore::~rggNucCore()
{
}

QString rggNucCore::extractLabel(QString const& el)
{ // Extract the label out of context menu action name
  QString seperator("(");
  QStringList ql = el.split(seperator);
  return ql[1].left(ql[1].size() - 1);
}

void rggNucCore::fillList(std::vector<std::pair<QString, smtk::model::EntityRef> >& l)
{
  auto generatePair = [](smtk::model::EntityRef& entity) {
    std::string newName;
    if (entity.hasStringProperty("label"))
    {
      newName = entity.name() + " (" + entity.stringProperty("label")[0] + ")";
    }
    else
    {
      newName = entity.name() + " ()";
    }
    return std::pair<QString, smtk::model::EntityRef>(QString::fromStdString(newName), entity);
  };

  // Add empty cell first
  if (m_resource)
  {
    if (m_resource->findEntitiesByProperty("label", "XX").size() > 0)
    {
      l.push_back(generatePair(m_resource->findEntitiesByProperty("label", "XX")[0]));
    }
  }
  smtk::model::EntityRefArray assies =
    m_resource->findEntitiesByProperty("rggType", Assembly::typeDescription);
  // Add all available assemblies that match the assembly's geometry type
  for (auto& assy : assies)
  {
    if (assy.as<smtk::model::Group>().isValid())
    {
      l.push_back(generatePair(assy));
    }
  }
}

smtk::model::EntityRef rggNucCore::getFromLabel(const QString& label)
{
  smtk::model::EntityRefArray assies = m_resource->findEntitiesByProperty("label", label.toStdString());
  for (auto& assy : assies)
  {
    if (assy.hasStringProperty("rggType") &&
      assy.stringProperty("rggType")[0] == Assembly::typeDescription)
    { // Each assy has a unique label
      return assy;
    }
  }
  return smtk::model::EntityRef();
}

bool rggNucCore::IsHexType()
{
  return this->m_lattice->GetGeometryType() == HEXAGONAL;
}

void rggNucCore::calculateExtraTranslation(double& transX, double& transY)
{
  (void)transX;
  (void)transY;
  // "TODO: rggNucCore::calculateExtraTranslation"
}

void rggNucCore::calculateTranslation(double& transX, double& transY)
{
  (void)transX;
  (void)transY;
  // "TODO: rggNucCore::calculateTranslation"
}

void rggNucCore::setUpdateUsed()
{
  // "TODO: rggNucCore::setUpdateUsed"
}

void rggNucCore::getRadius(double& ri, double& rj) const
{
  (void)ri;
  (void)rj;
  // "TODO: rggNucCore::getRadius"
}

void rggNucCore::resetBySMTKCore(const smtk::model::EntityRef& coreGroup)
{
  this->m_entity = coreGroup;
  smtk::model::Model model = coreGroup.owningModel();

  if (!coreGroup.isGroup() || !coreGroup.hasStringProperty(Core::propDescription))
  {
    smtkErrorMacro(smtk::io::Logger::instance(), "A invalid type core is passed"
                                                 " into rggNucCore!");
    return;
  }
  Core core =  json::parse(coreGroup.stringProperty(Core::propDescription)[0]);

  int isHex = core.geomType() == Core::GeomType::Hex;
  this->m_lattice->SetGeometryType(
    isHex ? rggGeometryType::HEXAGONAL : rggGeometryType::RECTILINEAR);

  this->m_lattice->SetDimensions(static_cast<size_t>(core.latticeSize().first),
                                 static_cast<size_t>(core.latticeSize().second));

  Core::UuidToSchema assyLayout = core.layout();
  for (auto& iter : assyLayout)
  {
    smtk::model::EntityRef assy = smtk::model::EntityRef(m_resource, iter.first);
    if (!assy.isValid())
    {
      smtkErrorMacro(
        smtk::io::Logger::instance(), "Core's assy ID " << iter.first << " is not valid");
      continue;
    }

    const auto& schema = iter.second;
    for (size_t i = 0; i < schema.size(); i++)
    {
      this->m_lattice->SetCell(static_cast<size_t>(schema[i].first),
            static_cast<size_t>(schema[i].second), assy);
    }
  }
}
