//=========================================================================
//  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/Assembly.h"
#include "smtk/session/rgg/json/jsonAssembly.h"

#include <string>

namespace smtk
{
namespace session
{
namespace rgg
{
using namespace smtk::model;
using json = nlohmann::json;
std::set<std::string> Assembly::s_usedLabels;

struct Assembly::Internal
{
  Internal()
  {
    this->centerPin = true;
  }
  std::string name;
  std::string label;
  FloatList color;
  double zAxis;
  double rotate;
  // Map each pin to its layouts
  // Rect: (i, j) where i is the index along width and y is along height.
  // Hex: (i, j) where i is the index along the ring and j is the index on that layer
  UuidToSchema layout;
  UuidToCoordinates coordinates;
  // x, y, z coordinates
  smtk::common::UUID assocatedDuct;
  bool centerPin;
  std::pair<double, double> pitch;
  std::pair<int, int> latticeSize;
  AssyExportParameters exportParams;
};

Assembly::Assembly() : m_internal(std::make_shared<Internal>())
{
}

Assembly::Assembly(const std::string& name,
                   const std::string& label) : m_internal(std::make_shared<Internal>())
{
  this->m_internal->name = name;
  this->m_internal->label = label;
  s_usedLabels.insert(label);
}

Assembly::~Assembly()
{
}

bool Assembly::isAnUniqueLabel(const std::string& label)
{
  return (s_usedLabels.find(label) ==s_usedLabels.end())?
        true : false;
}

std::string Assembly::generateUniqueLabel()
{
  int count = 0;
  std::string label = "A0";
  while(s_usedLabels.find(label) != s_usedLabels.end())
  {
    count++;
    label = "A" + std::to_string(count);
  }
  return label;
}

const std::string& Assembly::name() const
{
  return this->m_internal->name;
}

const std::string& Assembly::label() const
{
  return this->m_internal->label;
}

const smtk::model::FloatList& Assembly::color() const
{
  return this->m_internal->color;
}

const double& Assembly::zAxis() const
{
  return this->m_internal->zAxis;
}

const double& Assembly::rotate() const
{
  return this->m_internal->rotate;
}

Assembly::UuidToSchema& Assembly::layout()
{
  return this->m_internal->layout;
}

const Assembly::UuidToSchema& Assembly::layout() const
{
  return this->m_internal->layout;
}

Assembly::UuidToCoordinates& Assembly::entityToCoordinates()
{
  return this->m_internal->coordinates;
}

const Assembly::UuidToCoordinates& Assembly::entityToCoordinates() const
{
  return this->m_internal->coordinates;
}

const smtk::common::UUID& Assembly::associatedDuct() const
{
  return this->m_internal->assocatedDuct;
}

bool Assembly::centerPin() const
{
  return this->m_internal->centerPin;
}

// Hex core only uses pitch0
const std::pair<double, double>& Assembly::pitch() const
{
  return this->m_internal->pitch;
}

// Hex core only uses size0
const std::pair<int, int>& Assembly::latticeSize() const
{
  return this->m_internal->latticeSize;
}

AssyExportParameters& Assembly::exportParams()
{
  return this->m_internal->exportParams;
}

const AssyExportParameters& Assembly::exportParams() const
{
  return this->m_internal->exportParams;
}

void Assembly::setName(const std::string& name)
{
  this->m_internal->name = name;
}

bool Assembly::setLabel(const std::string& label)
{
  m_internal->label = label;
  s_usedLabels.insert(label);
  return true;
}

void Assembly::setColor(const smtk::model::FloatList& color)
{
  this->m_internal->color = color;
}

void Assembly::setZAxis(const double& zAxis)
{
  this->m_internal->zAxis = zAxis;
}

void Assembly::setRotate(const double& rotate)
{
  this->m_internal->rotate = rotate;
}

void Assembly::setLayout(const UuidToSchema& layout)
{
  this->m_internal->layout = layout;
}

void Assembly::setEntityToCoordinates(const UuidToCoordinates& uTC)
{
  this->m_internal->coordinates = uTC;
}

void Assembly::setAssociatedDuct(const smtk::common::UUID& duct)
{
  this->m_internal->assocatedDuct = duct;
}

void Assembly::setCenterPin(bool centerPin)
{
  this->m_internal->centerPin = centerPin;
}

// Hex core only uses pitch0
void Assembly::setPitch(const double& p0, const double& p1)
{
  this->m_internal->pitch = std::make_pair(p0, p1);
}

// Hex core only uses size0
void Assembly::setLatticeSize(const int& s0, const int& s1)
{
  this->m_internal->latticeSize = std::make_pair(s0, s1);
}

void Assembly::setLatticeSize(const std::pair<int, int>& ls)
{
  this->m_internal->latticeSize = ls;
}

void Assembly::setExportParams(const AssyExportParameters& aep)
{
  this->m_internal->exportParams = aep;
}

bool Assembly::operator==(const Assembly& other) const
{
  json thisA = *this;
  json otherA = other;
  return (thisA==otherA);
}

bool Assembly::operator!=(const Assembly& other) const
{
  return !(*this == other);
}

}
}
}
