//=========================================================================
//  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.
//=========================================================================
#ifndef smtk_session_aeva_Operation_h
#define smtk_session_aeva_Operation_h

#include "smtk/attribute/ReferenceItem.h"
#include "smtk/operation/XMLOperation.h"
#include "smtk/session/aeva/Exports.h"

#include "vtkSmartPointer.h"

class vtkDataObject;

namespace smtk
{
namespace session
{
namespace aeva
{

class Resource;
class Session;
typedef smtk::shared_ptr<Session> SessionPtr;
struct EntityHandle;

/**\brief An operator using the AEVA "kernel."
  *
  * This is a base class for actual operators.
  * It provides convenience methods for accessing AEVA-specific data
  * for its subclasses to use internally.
  */
class SMTKAEVASESSION_EXPORT Operation : public smtk::operation::XMLOperation
{
public:
  /// Return the VTK data object (if any) defining the given component.
  ///
  /// Note that this need not be the same as the data object returned by
  /// the resource's Geometry object.
  static vtkSmartPointer<vtkDataObject> storage(const smtk::resource::PersistentObject* obj);
  static vtkSmartPointer<vtkDataObject> storage(
    const std::shared_ptr<smtk::resource::PersistentObject>& obj);

  /// Use the operation's logic for retrieving a resource and session.
  static bool fetchResourceAndSession(const smtk::attribute::ReferenceItemPtr& assoc,
    std::shared_ptr<Resource>& resource,
    std::shared_ptr<Session>& session);

protected:
  /// Return the resource and session of the first valid associated component.
  ///
  /// This method is intended for use in ableToOperate().
  /// Unlike prepareResourceAndSession(), this method will never create a
  /// resource or session; instead it will return false if none can be
  /// identified.
  /// If you are invoking a method inside operateInternal, you should
  /// use prepareResourceAndSession() instead.
  bool fetchResourceAndSession(std::shared_ptr<Resource>& resource,
    std::shared_ptr<Session>& session) const;

  /// Use the resource and session of associated objects
  /// or, if allowCreate is true, create a resource and session otherwise.
  ///
  /// If a new resource is created, this method will look
  /// in the provided result object for a "resource" item
  /// and append it.
  void prepareResourceAndSession(Result& result,
    std::shared_ptr<Resource>& resource,
    std::shared_ptr<Session>& session,
    bool allowCreate = true);

  /// Return true if the given reference item holds values that
  /// have VTK data in the session and false otherwise.
  static bool allValuesHaveStorage(const smtk::attribute::ReferenceItem& item);

  static vtkSmartPointer<vtkDataObject> getData(const smtk::resource::PersistentObjectPtr& ptr);
};

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

#endif
