//=========================================================================
//  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_Boolean_h
#define smtk_session_aeva_Boolean_h

#include "smtk/session/aeva/Operation.h"
#include "smtk/session/aeva/Resource.h"

#include "smtk/model/Model.h"

#include "vtkSmartPointer.h"

class vtkDataObject;

namespace smtk
{
namespace session
{
namespace aeva
{

/// Perform boolean set operations on side-set primitives by global ID.
class SMTKAEVASESSION_EXPORT Boolean : public Operation
{
public:
  smtkTypeMacro(smtk::session::aeva::Boolean);
  smtkCreateMacro(Boolean);
  smtkSharedFromThisMacro(smtk::operation::Operation);
  smtkSuperclassMacro(Operation);

  bool ableToOperate() override;

  /// The type of operation to perform on the set of primitives.
  ///
  /// Keep this enum in sync with the values in Boolean.sbt.
  enum BooleanOpType
  {
    Unite = 0,     //!< Compute the union of the primitives.
    Intersect = 1, //!< Compute the intersection of the workpiece and tool primitives.
    Subtract = 2,  //!< Compute the difference between the workpiece and tool primitives.
    SubtractSymmetrically =
      3 //!< Compute the union of all differences between workpieces and tools.
  };

  /// Return the type of operation to perform on the inputs.
  ///
  /// This class inspects its parameters to determine the type.
  /// Subclasses that perform a single operation override this method
  /// as their parameters do not include this information.
  virtual BooleanOpType type() const;

protected:
  /// Compute the union of all inputs.
  static bool unite(const std::set<smtk::model::Entity*>& inputs,
    Session& session,
    vtkSmartPointer<vtkDataObject>& resultData,
    smtk::model::Model& parent);
  /// Compute the intersection of each workpiece with all tools.
  static bool intersect(const std::shared_ptr<smtk::attribute::ReferenceItem>& workpieces,
    const std::shared_ptr<smtk::attribute::ComponentItem>& tools,
    Session& session,
    vtkSmartPointer<vtkDataObject>& resultData,
    smtk::model::Model& parent);
  /// Subtract every tool from each workpiece.
  static bool subtract(const std::shared_ptr<smtk::attribute::ReferenceItem>& workpieces,
    const std::shared_ptr<smtk::attribute::ComponentItem>& tools,
    Session& session,
    vtkSmartPointer<vtkDataObject>& resultData,
    smtk::model::Model& parent);
  /// Compute the symmetric difference of all the inputs (i.e.,
  /// compute the portion of each input unique across all inputs and
  /// return the union of all of these).
  static bool symmetricSubtract(const std::set<smtk::model::Entity*>& inputs,
    Session& session,
    vtkSmartPointer<vtkDataObject>& resultData,
    smtk::model::Model& parent);

  Result operateInternal() override;
  const char* xmlDescription() const override;
};

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

#endif // smtk_session_aeva_Boolean_h
