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

  Program:   ParaView
  Module:    vtkPVDataInformation.h

  Copyright (c) Kitware, Inc.
  All rights reserved.
  See Copyright.txt or http://www.paraview.org/HTML/Copyright.html 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   vtkPVDataInformation
 * @brief   Light object for holding data information.
 *
 * This object is a light weight object.  It has no user interface and
 * does not necessarily last a long time.  It is meant to help collect
 * information about data object and collections of data objects.  It
 * has a PV in the class name because it should never be moved into
 * VTK.
 *
 * @warning
 * Get polygons only works for poly data and it does not work propelry for the
 * triangle strips.
*/

#ifndef vtkPVDataInformation_h
#define vtkPVDataInformation_h

#include "vtkPVClientServerCoreCoreModule.h" //needed for exports
#include "vtkPVInformation.h"

class vtkCollection;
class vtkCompositeDataSet;
class vtkDataObject;
class vtkDataSet;
class vtkGenericDataSet;
class vtkGraph;
class vtkHyperTreeGrid;
class vtkInformation;
class vtkPVArrayInformation;
class vtkPVCompositeDataInformation;
class vtkPVDataSetAttributesInformation;
class vtkPVDataInformationHelper;
class vtkSelection;
class vtkTable;

class VTKPVCLIENTSERVERCORECORE_EXPORT vtkPVDataInformation : public vtkPVInformation
{
public:
  static vtkPVDataInformation* New();
  vtkTypeMacro(vtkPVDataInformation, vtkPVInformation);
  void PrintSelf(ostream& os, vtkIndent indent) VTK_OVERRIDE;

  /**
   * Method to find and return attribute array information for a particular
   * array for the given attribute type if one exists.
   * Returns NULL if none is found.
   * \c fieldAssociation can be vtkDataObject::FIELD_ASSOCIATION_POINTS,
   * vtkDataObject::FIELD_ASSOCIATION_CELLS etc.
   * (use vtkDataObject::FIELD_ASSOCIATION_NONE for field data) (or
   * vtkDataObject::POINT, vtkDataObject::CELL, vtkDataObject::FIELD).
   */
  vtkPVArrayInformation* GetArrayInformation(const char* arrayname, int fieldAssociation);

  //@{
  /**
   * Port number controls which output port the information is gathered from.
   * This is the only parameter that can be set on  the client-side before
   * gathering the information.
   */
  vtkSetMacro(PortNumber, int);
  vtkGetMacro(PortNumber, int);
  //@}

  /**
   * Transfer information about a single object into this object.
   */
  void CopyFromObject(vtkObject*) VTK_OVERRIDE;

  /**
   * Merge another information object. Calls AddInformation(info, 0).
   */
  void AddInformation(vtkPVInformation* info) VTK_OVERRIDE;

  /**
   * Merge another information object. If adding information of
   * 1 part across processors, set addingParts to false. If
   * adding information of parts, set addingParts to true.
   */
  virtual void AddInformation(vtkPVInformation*, int addingParts);

  //@{
  /**
   * Manage a serialized version of the information.
   */
  void CopyToStream(vtkClientServerStream*) VTK_OVERRIDE;
  void CopyFromStream(const vtkClientServerStream*) VTK_OVERRIDE;
  //@}

  //@{
  /**
   * Serialize/Deserialize the parameters that control how/what information is
   * gathered. This are different from the ivars that constitute the gathered
   * information itself. For example, PortNumber on vtkPVDataInformation
   * controls what output port the data-information is gathered from.
   */
  void CopyParametersToStream(vtkMultiProcessStream&) VTK_OVERRIDE;
  void CopyParametersFromStream(vtkMultiProcessStream&) VTK_OVERRIDE;
  //@}

  /**
   * Remove all information.  The next add will be like a copy.
   * I might want to put this in the PVInformation superclass.
   */
  void Initialize();

  //@{
  /**
   * Access to information.
   */
  vtkGetMacro(DataSetType, int);
  vtkGetMacro(CompositeDataSetType, int);
  const char* GetDataSetTypeAsString();
  int DataSetTypeIsA(const char* type);
  vtkGetMacro(NumberOfPoints, vtkTypeInt64);
  vtkGetMacro(NumberOfCells, vtkTypeInt64);
  vtkGetMacro(NumberOfRows, vtkTypeInt64);
  vtkGetMacro(NumberOfTrees, vtkTypeInt64);
  vtkGetMacro(NumberOfVertices, vtkTypeInt64);
  vtkGetMacro(NumberOfLeaves, vtkTypeInt64);
  vtkGetMacro(MemorySize, int);
  vtkGetMacro(PolygonCount, int);
  vtkGetMacro(NumberOfDataSets, int);
  vtkGetVector6Macro(Bounds, double);
  //@}

  /**
   * Returns the number of elements of the given type where type can
   * vtkDataObject::POINT, vtkDataObject::CELL, ... etc.
   */
  vtkTypeInt64 GetNumberOfElements(int type);

  /**
   * Returns a string describing the datatype that can be directly
   * shown in a user interface.
   */
  const char* GetPrettyDataTypeString();

  //@{
  /**
   * Of course Extent is only valid for structured data sets.
   * Extent is the largest extent that contains all the parts.
   */
  vtkGetVector6Macro(Extent, int);
  //@}

  //@{
  /**
   * Access to information about points. Only valid for subclasses
   * of vtkPointSet.
   */
  vtkGetObjectMacro(PointArrayInformation, vtkPVArrayInformation);
  //@}

  //@{
  /**
   * Access to information about point/cell/vertex/edge/row data.
   */
  vtkGetObjectMacro(PointDataInformation, vtkPVDataSetAttributesInformation);
  vtkGetObjectMacro(CellDataInformation, vtkPVDataSetAttributesInformation);
  vtkGetObjectMacro(VertexDataInformation, vtkPVDataSetAttributesInformation);
  vtkGetObjectMacro(EdgeDataInformation, vtkPVDataSetAttributesInformation);
  vtkGetObjectMacro(RowDataInformation, vtkPVDataSetAttributesInformation);
  //@}

  //@{
  /**
   * Accesse to information about field data, if any.
   */
  vtkGetObjectMacro(FieldDataInformation, vtkPVDataSetAttributesInformation);
  //@}

  /**
   * Method to access vtkPVDataSetAttributesInformation using field association
   * type.
   * \c fieldAssociation can be vtkDataObject::FIELD_ASSOCIATION_POINTS,
   * vtkDataObject::FIELD_ASSOCIATION_CELLS etc.
   * (use vtkDataObject::FIELD_ASSOCIATION_NONE for field data).
   */
  vtkPVDataSetAttributesInformation* GetAttributeInformation(int fieldAssociation);

  //@{
  /**
   * If data is composite, this provides information specific to
   * composite datasets.
   */
  vtkGetObjectMacro(CompositeDataInformation, vtkPVCompositeDataInformation);
  //@}

  /**
   * Given the flat-index for a node in a composite dataset, this method returns
   * the data information for the node, it available.
   */
  vtkPVDataInformation* GetDataInformationForCompositeIndex(int index);

  /**
   * Compute the number of block leaf from this information
   * multipieces are counted as single block.
   * The boolean skipEmpty parameter allows to choose to count empty dataset are not
   * Calling this method with skipEmpty to false will correspond to the vtkBlockColors array
   * in a multiblock.
   */
  unsigned int GetNumberOfBlockLeafs(bool skipEmpty);

  /**
   * This is same as GetDataInformationForCompositeIndex() however note that the
   * index will get modified in this method.
   */
  vtkPVDataInformation* GetDataInformationForCompositeIndex(int* index);

  //@{
  /**
   * ClassName of the data represented by information object.
   */
  vtkGetStringMacro(DataClassName);
  //@}

  //@{
  /**
   * The least common class name of composite dataset blocks
   */
  vtkGetStringMacro(CompositeDataClassName);
  //@}

  vtkGetVector2Macro(TimeSpan, double);

  //@{
  /**
   * Returns if the Time is set.
   */
  vtkGetMacro(HasTime, int);
  //@}

  //@{
  /**
   * Returns the data time if, GetHasTime() return true.
   */
  vtkGetMacro(Time, double);
  //@}

  //@{
  /**
   * Returns the number of time steps.
   */
  vtkGetMacro(NumberOfTimeSteps, int);
  //@}

  //@{
  /**
   * Returns the label that should be used instead of "Time" if any.
   */
  vtkGetStringMacro(TimeLabel);
  //@}

  /**
   * Returns if the data type is structured.
   */
  int IsDataStructured();

  //@{
  /**
   * If this instance of vtkPVDataInformation summarizes a node in a
   * composite-dataset, and if that node has been given a label in that
   * composite dataset (using vtkCompositeDataSet::NAME meta-data), then this
   * will return that name. Returns NULL if this instance doesn't represent a
   * node in a composite dataset or doesn't have a label/name associated with
   * it.
   */
  vtkGetStringMacro(CompositeDataSetName);
  //@}

  /**
   * Allows run time addition of information getters for new classes
   */
  static void RegisterHelper(const char* classname, const char* helperclassname);

protected:
  vtkPVDataInformation();
  ~vtkPVDataInformation() override;

  void DeepCopy(vtkPVDataInformation* dataInfo, bool copyCompositeInformation = true);

  void AddFromMultiPieceDataSet(vtkCompositeDataSet* data);
  void CopyFromCompositeDataSet(vtkCompositeDataSet* data);
  void CopyFromCompositeDataSetInitialize(vtkCompositeDataSet* data);
  void CopyFromCompositeDataSetFinalize(vtkCompositeDataSet* data);
  virtual void CopyFromDataSet(vtkDataSet* data);
  void CopyFromGenericDataSet(vtkGenericDataSet* data);
  void CopyFromGraph(vtkGraph* graph);
  void CopyFromTable(vtkTable* table);
  void CopyFromHyperTreeGrid(vtkHyperTreeGrid* data);
  void CopyFromSelection(vtkSelection* selection);
  void CopyCommonMetaData(vtkDataObject*, vtkInformation*);

  static vtkPVDataInformationHelper* FindHelper(const char* classname);

  // Data information collected from remote processes.
  int DataSetType;
  int CompositeDataSetType;
  int NumberOfDataSets;
  vtkTypeInt64 NumberOfPoints; // data sets
  vtkTypeInt64 NumberOfCells;
  vtkTypeInt64 NumberOfRows;  // tables
  vtkTypeInt64 NumberOfTrees; // hypertreegrids
  vtkTypeInt64 NumberOfVertices;
  vtkTypeInt64 NumberOfLeaves;
  int MemorySize;
  vtkIdType PolygonCount;
  double Bounds[6];
  int Extent[6];
  double TimeSpan[2];
  double Time;
  int HasTime;
  int NumberOfTimeSteps;

  char* DataClassName;
  vtkSetStringMacro(DataClassName);

  char* TimeLabel;
  vtkSetStringMacro(TimeLabel);

  char* CompositeDataClassName;
  vtkSetStringMacro(CompositeDataClassName);

  char* CompositeDataSetName;
  vtkSetStringMacro(CompositeDataSetName);

  vtkPVDataSetAttributesInformation* PointDataInformation;
  vtkPVDataSetAttributesInformation* CellDataInformation;
  vtkPVDataSetAttributesInformation* FieldDataInformation;
  vtkPVDataSetAttributesInformation* VertexDataInformation;
  vtkPVDataSetAttributesInformation* EdgeDataInformation;
  vtkPVDataSetAttributesInformation* RowDataInformation;

  vtkPVCompositeDataInformation* CompositeDataInformation;

  vtkPVArrayInformation* PointArrayInformation;

  friend class vtkPVDataInformationHelper;
  friend class vtkPVCompositeDataInformation;

private:
  vtkPVDataInformation(const vtkPVDataInformation&) = delete;
  void operator=(const vtkPVDataInformation&) = delete;

  int PortNumber;
};

#endif
