//=========================================================================
//  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_Predicates_h
#define smtk_session_aeva_Predicates_h

#include "smtk/SharedPtr.h"
#include "smtk/session/aeva/Exports.h"

#include "vtkDataObject.h"
#include "vtkSmartPointer.h"

#include <functional>

class vtkPolyData;
class vtkDataSet;
class vtkDataArray;

namespace smtk
{
namespace model
{
class EntityRef;
}

namespace attribute
{
class ComponentItem;
}

namespace operation
{
class MarkGeometry;
}

namespace session
{
namespace aeva
{

/// The number of cells in a data object (or -1 if null or not applicable).
///
/// The base vtkDataObject class does not provide a method for this, but it should.
vtkIdType SMTKAEVASESSION_EXPORT NumberOfCells(const vtkSmartPointer<vtkDataObject>& data);

/// Given a cell type, return the parametric dimension of the cell or -1 if unknown/invalid.
int SMTKAEVASESSION_EXPORT DimensionFromCellType(int cellType);

/// Return the highest dimension of a few sampled cells.
///
/// Returns -1 for null data or data of inappropriate type (e.g., vtkTable).
int SMTKAEVASESSION_EXPORT EstimateParametricDimension(const vtkSmartPointer<vtkDataObject>& data);

/// Return whether the data represents cells or points.
///
/// This is currently determined by calling EstimateParametricDimension.
/// If the cell types are 0-dimensional, then POINT is returned. Otherwise
/// CELL is returned. If the input is not of the proper type, then
/// NUMBER_OF_ATTRIBUTE_TYPES is returned
vtkDataObject::AttributeTypes SMTKAEVASESSION_EXPORT EntityType(
  const vtkSmartPointer<vtkDataObject>& data);

/// Whether to iterate or not.
enum Iterate
{
  Continue, //!< Continue iterating; do not terminate.
  Break     //!< Stop iterating; terminate early.
};

/// A functor invoked on edge neighbors of a cell. Return Break to terminate early; Continue otherwise.
using EdgeNeighborVisitor = std::function<Iterate(vtkIdType neighboringFaceId)>;

/// A functor that visits edge neighbors of a cell.
using EdgeNeighborLambda = std::function<void(vtkIdType cellId, const EdgeNeighborVisitor&)>;

/// Return a lambda that can be used to visit edge-neighbors of 2-D surface cells.
///
/// The lambda can be called repeatedly and avoids the overhead of determining the
/// dataset-type of the input object for each call. Each time the lambda is called
/// with a visitor, that visitor is invoked once per edge-neighbor.
EdgeNeighborLambda SMTKAEVASESSION_EXPORT EdgeNeighbors(const vtkSmartPointer<vtkDataObject>& data);

/// Given poly-data or unstructured-grid \a data, return polydata with cell-normals.
///
/// This is used by several operations that require surface-normals.
/// Care is taken that the surface has the same number of cells as the input
/// (when the input is a surface) to ensure that cell IDs correspond to the inputs.
void SMTKAEVASESSION_EXPORT SurfaceWithNormals(const vtkSmartPointer<vtkDataObject>& data,
  vtkSmartPointer<vtkPolyData>& surf,
  vtkSmartPointer<vtkDataArray>& norm);

smtk::model::EntityRef SMTKAEVASESSION_EXPORT CreateCellForData(smtk::model::EntityRef& parent,
  vtkSmartPointer<vtkDataObject> const& data,
  smtk::shared_ptr<smtk::attribute::ComponentItem>& created,
  int& count,
  smtk::operation::MarkGeometry& marker,
  long pointIdOffset,
  long cellIdOffset,
  long& maxPointId,
  long& maxCellId);

}
}
}

#endif // smtk_session_aeva_Predicates_h
