/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkSimpleScalarTree.h

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm 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.

=========================================================================*/
/**
 * @class   vtkSimpleScalarTree
 * @brief   organize data according to scalar values (used to accelerate contouring operations)
 *
 * vtkSimpleScalarTree creates a pointerless binary tree that helps search
 * for cells that lie within a particular scalar range. This object is used
 * to accelerate some contouring (and other scalar-based techniques).
 *
 * The tree consists of an array of (min,max) scalar range pairs per
 * node in the tree. The (min,max) range is determined from looking at
 * the range of the children of the tree node. If the node is a leaf,
 * then the range is determined by scanning the range of scalar data
 * in n cells in the dataset. The n cells are determined by arbitrary
 * selecting cell ids from id(i) to id(i+n), and where n is specified
 * using the BranchingFactor ivar. Note that leaf node i=0 contains
 * the scalar range computed from cell ids (0,n-1); leaf node i=1
 * contains the range from cell ids (n,2n-1); and so on. The
 * implication is that there are no direct lists of cell ids per leaf
 * node, instead the cell ids are implicitly known. Despite the
 * arbitrary grouping of cells, in practice this scalar tree actually
 * performs quite well due to spatial/data coherence.
 *
 * This class has an API that supports both serial and parallel
 * operation.  The parallel API enables the using class to grab arrays
 * (or batches) of cells that potentially intersect the
 * isocontour. These batches can then be processed in separate
 * threads.
 *
 * @sa
 * vtkScalarTree vtkSpanSpace
 */

#ifndef vtkSimpleScalarTree_h
#define vtkSimpleScalarTree_h

#include "vtkCommonExecutionModelModule.h" // For export macro
#include "vtkScalarTree.h"

class vtkScalarNode;
class vtkSimpleScalarTree;

class VTKCOMMONEXECUTIONMODEL_EXPORT vtkSimpleScalarTree : public vtkScalarTree
{
public:
  /**
   * Instantiate scalar tree with maximum level of 20 and branching
   * factor of three.
   */
  static vtkSimpleScalarTree* New();

  //@{
  /**
   * Standard type related macros and PrintSelf() method.
   */
  vtkTypeMacro(vtkSimpleScalarTree, vtkScalarTree);
  void PrintSelf(ostream& os, vtkIndent indent) override;
  //@}

  /**
   * This method is used to copy data members when cloning an instance of the
   * class. It does not copy heavy data.
   */
  void ShallowCopy(vtkScalarTree* stree) override;

  //@{
  /**
   * Set the branching factor for the tree. This is the number of
   * children per tree node. Smaller values (minimum is 2) mean deeper
   * trees and more memory overhead. Larger values mean shallower
   * trees, less memory usage, but worse performance.
   */
  vtkSetClampMacro(BranchingFactor, int, 2, VTK_INT_MAX);
  vtkGetMacro(BranchingFactor, int);
  //@}

  //@{
  /**
   * Get the level of the scalar tree. This value may change each time the
   * scalar tree is built and the branching factor changes.
   */
  vtkGetMacro(Level, int);
  //@}

  //@{
  /**
   * Set the maximum allowable level for the tree.
   */
  vtkSetClampMacro(MaxLevel, int, 1, VTK_INT_MAX);
  vtkGetMacro(MaxLevel, int);
  //@}

  /**
   * Construct the scalar tree from the dataset provided. Checks build times
   * and modified time from input and reconstructs the tree if necessary.
   */
  void BuildTree() override;

  /**
   * Initialize locator. Frees memory and resets object as appropriate.
   */
  void Initialize() override;

  /**
   * Begin to traverse the cells based on a scalar value. Returned cells
   * will likely have scalar values that span the scalar value specified.
   */
  void InitTraversal(double scalarValue) override;

  /**
   * Return the next cell that may contain scalar value specified to
   * initialize traversal. The value nullptr is returned if the list is
   * exhausted. Make sure that InitTraversal() has been invoked first or
   * you'll get erratic behavior.
   */
  vtkCell* GetNextCell(vtkIdType& cellId, vtkIdList*& ptIds, vtkDataArray* cellScalars) override;

  // The following methods supports parallel (threaded) traversal. Basically
  // batches of cells (which are a portion of the whole dataset) are available for
  // processing in a parallel For() operation.

  /**
   * Get the number of cell batches available for processing as a function of
   * the specified scalar value. Each batch contains a list of candidate
   * cells that may contain the specified isocontour value.
   */
  vtkIdType GetNumberOfCellBatches(double scalarValue) override;

  /**
   * Return the array of cell ids in the specified batch. The method
   * also returns the number of cell ids in the array. Make sure to
   * call GetNumberOfCellBatches() beforehand.
   */
  const vtkIdType* GetCellBatch(vtkIdType batchNum, vtkIdType& numCells) override;

protected:
  vtkSimpleScalarTree();
  ~vtkSimpleScalarTree() override;

  int MaxLevel;
  int Level;
  int BranchingFactor;  // number of children per node
  vtkScalarNode* Tree;  // pointerless scalar range tree
  int TreeSize;         // allocated size of tree
  vtkIdType LeafOffset; // offset to leaf nodes of tree

private:
  vtkIdType NumCells;  // the number of cells in this dataset
  vtkIdType TreeIndex; // traversal location within tree
  int ChildNumber;     // current child in traversal
  vtkIdType CellId;    // current cell id being examined
  int FindStartLeaf(vtkIdType index, int level);
  int FindNextLeaf(vtkIdType index, int level);

  vtkIdType* CandidateCells; // to support parallel computing
  vtkIdType NumCandidates;

private:
  vtkSimpleScalarTree(const vtkSimpleScalarTree&) = delete;
  void operator=(const vtkSimpleScalarTree&) = delete;
};

#endif
