//=========================================================================
//  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/aeva/Operation.h"
#include "smtk/session/aeva/Resource.h"
#include "smtk/session/aeva/Session.h"

#include "smtk/attribute/Attribute.h"
#include "smtk/attribute/ReferenceItem.h"
#include "smtk/attribute/Resource.h"
#include "smtk/attribute/ResourceItem.h"

#include "vtkDataObject.h"

namespace smtk
{
namespace session
{
namespace aeva
{

vtkSmartPointer<vtkDataObject> Operation::storage(const smtk::resource::PersistentObject* obj)
{
  vtkSmartPointer<vtkDataObject> result;
  if (const auto* comp = dynamic_cast<const smtk::resource::Component*>(obj))
  {
    auto* resource = dynamic_cast<Resource*>(comp->resource().get());
    if (resource && resource->session())
    {
      result = resource->session()->findStorage(comp->id());
    }
  }
  else if (const auto* rsrc = dynamic_cast<const Resource*>(obj))
  {
    result = rsrc->session()->findStorage(rsrc->id());
  }
  return result;
}

vtkSmartPointer<vtkDataObject> Operation::storage(
  const std::shared_ptr<smtk::resource::PersistentObject>& obj)
{
  return Operation::storage(obj.get());
}

bool Operation::fetchResourceAndSession(const smtk::attribute::ReferenceItemPtr& assoc,
  std::shared_ptr<Resource>& resource,
  std::shared_ptr<Session>& session)
{
  if (assoc && assoc->isEnabled() && assoc->isSet(0))
  {
    resource = dynamic_pointer_cast<Resource>(assoc->value(0));
    if (!resource)
    {
      auto comp = dynamic_pointer_cast<smtk::resource::Component>(assoc->value(0));
      if (comp)
      {
        resource = dynamic_pointer_cast<Resource>(comp->resource());
      }
    }
    if (resource)
    {
      session = resource->session();
    }
  }
  return resource && session;
}

bool Operation::fetchResourceAndSession(std::shared_ptr<Resource>& resource,
  std::shared_ptr<Session>& session) const
{
  return Operation::fetchResourceAndSession(this->parameters()->associations(), resource, session);
}

void Operation::prepareResourceAndSession(Result& result,
  std::shared_ptr<Resource>& resource,
  std::shared_ptr<Session>& session,
  bool allowCreate)
{
  this->fetchResourceAndSession(resource, session);

  // Create a new resource for the import if needed.
  if (!resource && allowCreate)
  {
    auto manager = this->specification()->manager();
    if (manager)
    {
      resource = manager->create<smtk::session::aeva::Resource>();
    }
    else
    {
      resource = smtk::session::aeva::Resource::create();
    }
    auto resultResources = result->findResource("resource");
    if (resultResources)
    {
      resultResources->appendValue(resource);
    }
  }
  if (!session && allowCreate)
  {
    session = smtk::session::aeva::Session::create();
    resource->setSession(session);
  }
}

bool Operation::allValuesHaveStorage(const smtk::attribute::ReferenceItem& item)
{
  for (std::size_t ii = 0; ii < item.numberOfValues(); ++ii)
  {
    if (!item.isSet(ii))
    {
      continue;
    }
    auto target = item.valueAs<smtk::resource::Component>(ii);
    auto resource = std::dynamic_pointer_cast<smtk::session::aeva::Resource>(target->resource());
    auto session = resource ? resource->session() : smtk::session::aeva::Session::Ptr();
    if (!session)
    {
      return false;
    }
    vtkSmartPointer<vtkDataObject> targetData;
    if (!target || !(targetData = session->findStorage(target->id())))
    {
      return false;
    }
  }
  return true;
}

vtkSmartPointer<vtkDataObject> Operation::getData(const smtk::resource::PersistentObjectPtr& ptr)
{
  // Get the model, resource, and session of the persistent object ptr
  smtk::model::Model model = ptr->as<smtk::model::Entity>()->owningModel();
  smtk::session::aeva::Resource::Ptr resource =
    model.resource()->as<smtk::session::aeva::Resource>();
  smtk::session::aeva::Session::Ptr session = resource->session();

  return session->findStorage(ptr->id());
}

} // namespace aeva
} //namespace session
} // namespace smtk
