//=============================================================================
// 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/operators/EditCore.h"

#include "smtk/session/rgg/Resource.h"
#include "smtk/session/rgg/Session.h"

#include "smtk/session/rgg/operators/CreateModel.h"
#include "smtk/session/rgg/operators/OperationHelper.h"

#include "smtk/io/Logger.h"

#include "smtk/attribute/Attribute.h"
#include "smtk/attribute/DoubleItem.h"
#include "smtk/attribute/ModelEntityItem.h"
#include "smtk/attribute/StringItem.h"

#include "smtk/model/Group.h"
#include "smtk/model/Instance.h"
#include "smtk/session/rgg/Assembly.h"
#include "smtk/session/rgg/Duct.h"
#include "smtk/session/rgg/operators/EditAssembly.h"

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

#include "smtk/session/rgg/EditCore_xml.h"

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

EditCore::Result EditCore::operateInternal()
{

  smtk::model::EntityRefArray entities =
    this->parameters()->associatedModelEntities<smtk::model::EntityRefArray>();
  if (entities.empty() || !entities[0].isGroup())
  {
    smtkErrorMacro(this->log(), "Cannot edit a non group type core");
    return this->createResult(smtk::operation::Operation::Outcome::FAILED);
  }
  Result result = this->createResult(smtk::operation::Operation::Outcome::SUCCEEDED);

  smtk::attribute::ComponentItem::Ptr createdItem = result->findComponent("created");
  smtk::attribute::ComponentItem::Ptr modifiedItem = result->findComponent("modified");
  smtk::attribute::ComponentItem::Ptr tessChangedItem = result->findComponent("tess_changed");
  smtk::attribute::ComponentItem::Ptr expungedItem = result->findComponent("expunged");

  smtk::model::EntityRefArray expunged, modified, tobeDeleted;

  smtk::model::Group coreGroup = entities[0].as<smtk::model::Group>();
  auto resource = coreGroup.resource();

  // Get core representation
  std::string coreRepStr;
  smtk::attribute::StringItemPtr coreRepItem = this->parameters()->
      findString("core representation");

  if (coreRepItem != nullptr && !coreRepItem->value(0).empty())
  {
    coreRepStr = coreRepItem->value(0);
  }
  Core core = json::parse(coreRepStr);
  coreGroup.setName(core.name());
  coreGroup.setStringProperty(Core::propDescription, coreRepStr);

  // Remove all current entities in the group
  auto groupMembers = coreGroup.members<smtk::model::EntityRefArray>();
  tobeDeleted.insert(tobeDeleted.begin(), groupMembers.begin(), groupMembers.end());
  for (auto& e : tobeDeleted)
  {
    expungedItem->appendValue(e.component());
  }

  // Glyph the used pins and ducts, then add them into the group
  Core::UuidToCoordinates& pDToCoords = core.pinsAndDuctsToCoordinates();
  OperationHelper::glyphDucts(resource,
                              createdItem,
                              modifiedItem, tessChangedItem,
                              coreGroup, pDToCoords, "Core");
  OperationHelper::glyphPins(resource,
                              createdItem,
                              modifiedItem, tessChangedItem,
                              coreGroup, pDToCoords, "Core");

  modifiedItem->appendValue(coreGroup.component());

  // Delete child aux geoms after being been appended to expunged item since once they
  // are deleted, the component of each aux geom would become invalid.
  resource->deleteEntities(tobeDeleted, modified, expunged, this->m_debugLevel > 0);
  return result;
}

const char* EditCore::xmlDescription() const
{
  return EditCore_xml;
}
} // namespace rgg
} //namespace session
} // namespace smtk
