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

Program:   Visualization Toolkit
Module:    vtkDataObject.cxx

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.

=========================================================================*/
#include "vtkDataObject.h"

#include "vtkDataSetAttributes.h"
#include "vtkFieldData.h"
#include "vtkGarbageCollector.h"
#include "vtkInformation.h"
#include "vtkInformationDataObjectKey.h"
#include "vtkInformationDoubleKey.h"
#include "vtkInformationDoubleVectorKey.h"
#include "vtkInformationInformationVectorKey.h"
#include "vtkInformationIntegerKey.h"
#include "vtkInformationIntegerPointerKey.h"
#include "vtkInformationIntegerVectorKey.h"
#include "vtkInformationStringKey.h"
#include "vtkInformationVector.h"
#include "vtkObjectFactory.h"
#include "vtkUnsignedCharArray.h"

VTK_ABI_NAMESPACE_BEGIN
vtkStandardNewMacro(vtkDataObject);

vtkCxxSetObjectMacro(vtkDataObject, Information, vtkInformation);
vtkCxxSetObjectMacro(vtkDataObject, FieldData, vtkFieldData);

vtkInformationKeyMacro(vtkDataObject, DATA_TYPE_NAME, String);
vtkInformationKeyMacro(vtkDataObject, DATA_OBJECT, DataObject);
vtkInformationKeyMacro(vtkDataObject, DATA_EXTENT_TYPE, Integer);
vtkInformationKeyMacro(vtkDataObject, DATA_PIECE_NUMBER, Integer);
vtkInformationKeyMacro(vtkDataObject, DATA_NUMBER_OF_PIECES, Integer);
vtkInformationKeyMacro(vtkDataObject, DATA_NUMBER_OF_GHOST_LEVELS, Integer);
vtkInformationKeyMacro(vtkDataObject, DATA_TIME_STEP, Double);
vtkInformationKeyMacro(vtkDataObject, POINT_DATA_VECTOR, InformationVector);
vtkInformationKeyMacro(vtkDataObject, CELL_DATA_VECTOR, InformationVector);
vtkInformationKeyMacro(vtkDataObject, VERTEX_DATA_VECTOR, InformationVector);
vtkInformationKeyMacro(vtkDataObject, EDGE_DATA_VECTOR, InformationVector);
vtkInformationKeyMacro(vtkDataObject, FIELD_ARRAY_TYPE, Integer);
vtkInformationKeyMacro(vtkDataObject, FIELD_ASSOCIATION, Integer);
vtkInformationKeyMacro(vtkDataObject, FIELD_ATTRIBUTE_TYPE, Integer);
vtkInformationKeyMacro(vtkDataObject, FIELD_ACTIVE_ATTRIBUTE, Integer);
vtkInformationKeyMacro(vtkDataObject, FIELD_NAME, String);
vtkInformationKeyMacro(vtkDataObject, FIELD_NUMBER_OF_COMPONENTS, Integer);
vtkInformationKeyMacro(vtkDataObject, FIELD_NUMBER_OF_TUPLES, Integer);
vtkInformationKeyRestrictedMacro(vtkDataObject, FIELD_RANGE, DoubleVector, 2);
vtkInformationKeyRestrictedMacro(vtkDataObject, PIECE_EXTENT, IntegerVector, 6);
vtkInformationKeyMacro(vtkDataObject, FIELD_OPERATION, Integer);
vtkInformationKeyRestrictedMacro(vtkDataObject, ALL_PIECES_EXTENT, IntegerVector, 6);
vtkInformationKeyRestrictedMacro(vtkDataObject, DATA_EXTENT, IntegerPointer, 6);
vtkInformationKeyRestrictedMacro(vtkDataObject, ORIGIN, DoubleVector, 3);
vtkInformationKeyRestrictedMacro(vtkDataObject, SPACING, DoubleVector, 3);
vtkInformationKeyRestrictedMacro(vtkDataObject, DIRECTION, DoubleVector, 9);
vtkInformationKeyMacro(vtkDataObject, SIL, DataObject);
vtkInformationKeyRestrictedMacro(vtkDataObject, BOUNDING_BOX, DoubleVector, 6);

// Initialize static member that controls global data release
// after use by filter
static vtkTypeBool vtkDataObjectGlobalReleaseDataFlag = 0;

// this list must be kept in-sync with the FieldAssociations enum
static const char* FieldAssociationsNames[] = { "vtkDataObject::FIELD_ASSOCIATION_POINTS",
  "vtkDataObject::FIELD_ASSOCIATION_CELLS", "vtkDataObject::FIELD_ASSOCIATION_NONE",
  "vtkDataObject::FIELD_ASSOCIATION_POINTS_THEN_CELLS", "vtkDataObject::FIELD_ASSOCIATION_VERTICES",
  "vtkDataObject::FIELD_ASSOCIATION_EDGES", "vtkDataObject::FIELD_ASSOCIATION_ROWS" };

// this list must be kept in-sync with the AttributeTypes enum
static const char* AttributeTypesNames[] = { "vtkDataObject::POINT", "vtkDataObject::CELL",
  "vtkDataObject::FIELD", "vtkDataObject::POINT_THEN_CELL", "vtkDataObject::VERTEX",
  "vtkDataObject::EDGE", "vtkDataObject::ROW" };

//------------------------------------------------------------------------------
vtkDataObject::vtkDataObject()
{
  this->Information = vtkInformation::New();

  // We have to assume that if a user is creating the data on their own,
  // then they will fill it with valid data.
  this->DataReleased = 0;

  this->FieldData = nullptr;
  vtkFieldData* fd = vtkFieldData::New();
  this->SetFieldData(fd);
  fd->FastDelete();
}

//------------------------------------------------------------------------------
vtkDataObject::~vtkDataObject()
{
  this->SetInformation(nullptr);
  this->SetFieldData(nullptr);
}

//------------------------------------------------------------------------------
void vtkDataObject::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os, indent);

  if (this->Information)
  {
    os << indent << "Information: " << this->Information << "\n";
  }
  else
  {
    os << indent << "Information: (none)\n";
  }

  os << indent << "Data Released: " << (this->DataReleased ? "True\n" : "False\n");
  os << indent
     << "Global Release Data: " << (vtkDataObjectGlobalReleaseDataFlag ? "On\n" : "Off\n");

  os << indent << "UpdateTime: " << this->UpdateTime << endl;

  os << indent << "Field Data:\n";
  this->FieldData->PrintSelf(os, indent.GetNextIndent());
}

//------------------------------------------------------------------------------
// Determine the modified time of this object
vtkMTimeType vtkDataObject::GetMTime()
{
  vtkMTimeType result;

  result = vtkObject::GetMTime();
  if (this->FieldData)
  {
    vtkMTimeType mtime = this->FieldData->GetMTime();
    result = (mtime > result ? mtime : result);
  }

  return result;
}

//------------------------------------------------------------------------------
void vtkDataObject::Initialize()
{
  if (this->FieldData)
  {
    this->FieldData->Initialize();
  }

  if (this->Information)
  {
    // Make sure the information is cleared.
    this->Information->Remove(ALL_PIECES_EXTENT());
    this->Information->Remove(DATA_PIECE_NUMBER());
    this->Information->Remove(DATA_NUMBER_OF_PIECES());
    this->Information->Remove(DATA_NUMBER_OF_GHOST_LEVELS());
    this->Information->Remove(DATA_TIME_STEP());
  }

  this->Modified();
}

//------------------------------------------------------------------------------
void vtkDataObject::SetGlobalReleaseDataFlag(vtkTypeBool val)
{
  if (val == vtkDataObjectGlobalReleaseDataFlag)
  {
    return;
  }
  vtkDataObjectGlobalReleaseDataFlag = val;
}

//------------------------------------------------------------------------------
vtkInformation* vtkDataObject::GetActiveFieldInformation(
  vtkInformation* info, int fieldAssociation, int attributeType)
{
  int i;
  vtkInformation* fieldDataInfo;
  vtkInformationVector* fieldDataInfoVector;

  if (fieldAssociation == FIELD_ASSOCIATION_POINTS)
  {
    fieldDataInfoVector = info->Get(POINT_DATA_VECTOR());
  }
  else if (fieldAssociation == FIELD_ASSOCIATION_CELLS)
  {
    fieldDataInfoVector = info->Get(CELL_DATA_VECTOR());
  }
  else if (fieldAssociation == FIELD_ASSOCIATION_VERTICES)
  {
    fieldDataInfoVector = info->Get(VERTEX_DATA_VECTOR());
  }
  else if (fieldAssociation == FIELD_ASSOCIATION_EDGES)
  {
    fieldDataInfoVector = info->Get(EDGE_DATA_VECTOR());
  }
  else
  {
    vtkGenericWarningMacro("Unrecognized field association!");
    return nullptr;
  }

  if (!fieldDataInfoVector)
  {
    return nullptr;
  }

  for (i = 0; i < fieldDataInfoVector->GetNumberOfInformationObjects(); i++)
  {
    fieldDataInfo = fieldDataInfoVector->GetInformationObject(i);
    if (fieldDataInfo->Has(FIELD_ACTIVE_ATTRIBUTE()) &&
      (fieldDataInfo->Get(FIELD_ACTIVE_ATTRIBUTE()) & (1 << attributeType)))
    {
      return fieldDataInfo;
    }
  }
  return nullptr;
}

//------------------------------------------------------------------------------
vtkInformation* vtkDataObject::GetNamedFieldInformation(
  vtkInformation* info, int fieldAssociation, const char* name)
{
  int i;
  vtkInformation* fieldDataInfo;
  vtkInformationVector* fieldDataInfoVector;

  if (fieldAssociation == FIELD_ASSOCIATION_POINTS)
  {
    fieldDataInfoVector = info->Get(POINT_DATA_VECTOR());
  }
  else if (fieldAssociation == FIELD_ASSOCIATION_CELLS)
  {
    fieldDataInfoVector = info->Get(CELL_DATA_VECTOR());
  }
  else if (fieldAssociation == FIELD_ASSOCIATION_VERTICES)
  {
    fieldDataInfoVector = info->Get(VERTEX_DATA_VECTOR());
  }
  else if (fieldAssociation == FIELD_ASSOCIATION_EDGES)
  {
    fieldDataInfoVector = info->Get(EDGE_DATA_VECTOR());
  }
  else
  {
    vtkGenericWarningMacro("Unrecognized field association!");
    return nullptr;
  }

  if (!fieldDataInfoVector)
  {
    return nullptr;
  }

  for (i = 0; i < fieldDataInfoVector->GetNumberOfInformationObjects(); i++)
  {
    fieldDataInfo = fieldDataInfoVector->GetInformationObject(i);
    if (fieldDataInfo->Has(FIELD_NAME()) && !strcmp(fieldDataInfo->Get(FIELD_NAME()), name))
    {
      return fieldDataInfo;
    }
  }
  return nullptr;
}

//------------------------------------------------------------------------------
void vtkDataObject::RemoveNamedFieldInformation(
  vtkInformation* info, int fieldAssociation, const char* name)
{
  int i;
  vtkInformation* fieldDataInfo;
  vtkInformationVector* fieldDataInfoVector;

  if (fieldAssociation == FIELD_ASSOCIATION_POINTS)
  {
    fieldDataInfoVector = info->Get(POINT_DATA_VECTOR());
  }
  else if (fieldAssociation == FIELD_ASSOCIATION_CELLS)
  {
    fieldDataInfoVector = info->Get(CELL_DATA_VECTOR());
  }
  else if (fieldAssociation == FIELD_ASSOCIATION_VERTICES)
  {
    fieldDataInfoVector = info->Get(VERTEX_DATA_VECTOR());
  }
  else if (fieldAssociation == FIELD_ASSOCIATION_EDGES)
  {
    fieldDataInfoVector = info->Get(EDGE_DATA_VECTOR());
  }
  else
  {
    vtkGenericWarningMacro("Unrecognized field association!");
    return;
  }

  if (!fieldDataInfoVector)
  {
    return;
  }

  for (i = 0; i < fieldDataInfoVector->GetNumberOfInformationObjects(); i++)
  {
    fieldDataInfo = fieldDataInfoVector->GetInformationObject(i);
    if (fieldDataInfo->Has(FIELD_NAME()) && !strcmp(fieldDataInfo->Get(FIELD_NAME()), name))
    {
      fieldDataInfoVector->Remove(fieldDataInfo);
      return;
    }
  }
}

//------------------------------------------------------------------------------
vtkInformation* vtkDataObject::SetActiveAttribute(
  vtkInformation* info, int fieldAssociation, const char* attributeName, int attributeType)
{
  int i;
  vtkInformation* fieldDataInfo;
  vtkInformationVector* fieldDataInfoVector;

  if (fieldAssociation == FIELD_ASSOCIATION_POINTS)
  {
    fieldDataInfoVector = info->Get(POINT_DATA_VECTOR());
  }
  else if (fieldAssociation == FIELD_ASSOCIATION_CELLS)
  {
    fieldDataInfoVector = info->Get(CELL_DATA_VECTOR());
  }
  else if (fieldAssociation == FIELD_ASSOCIATION_VERTICES)
  {
    fieldDataInfoVector = info->Get(VERTEX_DATA_VECTOR());
  }
  else if (fieldAssociation == FIELD_ASSOCIATION_EDGES)
  {
    fieldDataInfoVector = info->Get(EDGE_DATA_VECTOR());
  }
  else
  {
    vtkGenericWarningMacro("Unrecognized field association!");
    return nullptr;
  }
  if (!fieldDataInfoVector)
  {
    fieldDataInfoVector = vtkInformationVector::New();
    if (fieldAssociation == FIELD_ASSOCIATION_POINTS)
    {
      info->Set(POINT_DATA_VECTOR(), fieldDataInfoVector);
    }
    else if (fieldAssociation == FIELD_ASSOCIATION_CELLS)
    {
      info->Set(CELL_DATA_VECTOR(), fieldDataInfoVector);
    }
    else if (fieldAssociation == FIELD_ASSOCIATION_VERTICES)
    {
      info->Set(VERTEX_DATA_VECTOR(), fieldDataInfoVector);
    }
    else // if (fieldAssociation == FIELD_ASSOCIATION_EDGES)
    {
      info->Set(EDGE_DATA_VECTOR(), fieldDataInfoVector);
    }
    fieldDataInfoVector->FastDelete();
  }

  // if we find a matching field, turn it on (active);  if another field of same
  // attribute type was active, turn it off (not active)
  vtkInformation* activeField = nullptr;
  int activeAttribute;
  const char* fieldName;
  for (i = 0; i < fieldDataInfoVector->GetNumberOfInformationObjects(); i++)
  {
    fieldDataInfo = fieldDataInfoVector->GetInformationObject(i);
    activeAttribute = fieldDataInfo->Get(FIELD_ACTIVE_ATTRIBUTE());
    fieldName = fieldDataInfo->Get(FIELD_NAME());
    // if names match (or both empty... no field name), then set active
    if ((attributeName && fieldName && !strcmp(attributeName, fieldName)) ||
      (!attributeName && !fieldName))
    {
      activeAttribute |= 1 << attributeType;
      fieldDataInfo->Set(FIELD_ACTIVE_ATTRIBUTE(), activeAttribute);
      activeField = fieldDataInfo;
    }
    else if (activeAttribute & (1 << attributeType))
    {
      activeAttribute &= ~(1 << attributeType);
      fieldDataInfo->Set(FIELD_ACTIVE_ATTRIBUTE(), activeAttribute);
    }
  }

  // if we didn't find a matching field, create one
  if (!activeField)
  {
    activeField = vtkInformation::New();
    activeField->Set(FIELD_ACTIVE_ATTRIBUTE(), 1 << attributeType);
    activeField->Set(FIELD_ASSOCIATION(), fieldAssociation);
    if (attributeName)
    {
      activeField->Set(FIELD_NAME(), attributeName);
    }
    fieldDataInfoVector->Append(activeField);
    activeField->FastDelete();
  }

  return activeField;
}

//------------------------------------------------------------------------------
void vtkDataObject::SetActiveAttributeInfo(vtkInformation* info, int fieldAssociation,
  int attributeType, const char* name, int arrayType, int numComponents, int numTuples)
{
  vtkInformation* attrInfo =
    vtkDataObject::GetActiveFieldInformation(info, fieldAssociation, attributeType);
  if (!attrInfo)
  {
    // create an entry and set it as active
    attrInfo = SetActiveAttribute(info, fieldAssociation, name, attributeType);
  }

  if (name)
  {
    attrInfo->Set(FIELD_NAME(), name);
  }

  // Set the scalar type if it was given.  If it was not given and
  // there is no current scalar type set the default to VTK_DOUBLE.
  if (arrayType != -1)
  {
    attrInfo->Set(FIELD_ARRAY_TYPE(), arrayType);
  }
  else if (!attrInfo->Has(FIELD_ARRAY_TYPE()))
  {
    attrInfo->Set(FIELD_ARRAY_TYPE(), VTK_DOUBLE);
  }

  // Set the number of components if it was given.  If it was not
  // given and there is no current number of components set the
  // default to 1.
  if (numComponents != -1)
  {
    attrInfo->Set(FIELD_NUMBER_OF_COMPONENTS(), numComponents);
  }
  else if (!attrInfo->Has(FIELD_NUMBER_OF_COMPONENTS()))
  {
    attrInfo->Set(FIELD_NUMBER_OF_COMPONENTS(), 1);
  }

  if (numTuples != -1)
  {
    attrInfo->Set(FIELD_NUMBER_OF_TUPLES(), numTuples);
  }
}

//------------------------------------------------------------------------------
void vtkDataObject::SetPointDataActiveScalarInfo(
  vtkInformation* info, int arrayType, int numComponents)
{
  vtkDataObject::SetActiveAttributeInfo(info, FIELD_ASSOCIATION_POINTS,
    vtkDataSetAttributes::SCALARS, nullptr, arrayType, numComponents, -1);
}

//------------------------------------------------------------------------------
void vtkDataObject::DataHasBeenGenerated()
{
  this->DataReleased = 0;
  this->UpdateTime.Modified();
}

//------------------------------------------------------------------------------
vtkTypeBool vtkDataObject::GetGlobalReleaseDataFlag()
{
  return vtkDataObjectGlobalReleaseDataFlag;
}

//------------------------------------------------------------------------------
void vtkDataObject::ReleaseData()
{
  this->Initialize();
  this->DataReleased = 1;
}

//------------------------------------------------------------------------------
vtkMTimeType vtkDataObject::GetUpdateTime()
{
  return this->UpdateTime.GetMTime();
}

//------------------------------------------------------------------------------

unsigned long vtkDataObject::GetActualMemorySize()
{
  return this->FieldData->GetActualMemorySize();
}

//------------------------------------------------------------------------------
void vtkDataObject::ShallowCopy(vtkDataObject* src)
{
  if (!src)
  {
    vtkWarningMacro("Attempted to ShallowCopy from null.");
    return;
  }

  if (src == this)
  {
    vtkWarningMacro("Attempted to ShallowCopy the data object into itself.");
    return;
  }

  this->InternalDataObjectCopy(src);

  if (!src->FieldData)
  {
    this->SetFieldData(nullptr);
  }
  else
  {
    if (this->FieldData)
    {
      this->FieldData->ShallowCopy(src->FieldData);
    }
    else
    {
      vtkFieldData* fd = vtkFieldData::New();
      fd->ShallowCopy(src->FieldData);
      this->SetFieldData(fd);
      fd->FastDelete();
    }
  }
}

//------------------------------------------------------------------------------
void vtkDataObject::DeepCopy(vtkDataObject* src)
{
  if (!src)
  {
    vtkWarningMacro("Attempted to DeepCopy from null.");
    return;
  }

  if (src == this)
  {
    vtkWarningMacro("Attempted to DeepCopy the data object into itself.");
    return;
  }

  vtkFieldData* srcFieldData = src->GetFieldData();

  this->InternalDataObjectCopy(src);

  if (srcFieldData)
  {
    vtkFieldData* newFieldData = vtkFieldData::New();
    newFieldData->DeepCopy(srcFieldData);
    this->SetFieldData(newFieldData);
    newFieldData->FastDelete();
  }
  else
  {
    this->SetFieldData(nullptr);
  }
}

//------------------------------------------------------------------------------
void vtkDataObject::InternalDataObjectCopy(vtkDataObject* src)
{
  this->DataReleased = src->DataReleased;

  // Do not copy pipeline specific information from data object to
  // data object. This meta-data is specific to the algorithm and the
  // what was requested of it when it executed. What looks like a single
  // piece to an internal algorithm may be a piece to an external
  // algorithm.
  /*
  if(src->Information->Has(DATA_PIECE_NUMBER()))
    {
    this->Information->Set(DATA_PIECE_NUMBER(),
                           src->Information->Get(DATA_PIECE_NUMBER()));
    }
  if(src->Information->Has(DATA_NUMBER_OF_PIECES()))
    {
    this->Information->Set(DATA_NUMBER_OF_PIECES(),
                           src->Information->Get(DATA_NUMBER_OF_PIECES()));
    }
  if(src->Information->Has(DATA_NUMBER_OF_GHOST_LEVELS()))
    {
    this->Information->Set(DATA_NUMBER_OF_GHOST_LEVELS(),
                           src->Information->Get(DATA_NUMBER_OF_GHOST_LEVELS()));
    }
  */
  if (src->Information->Has(DATA_TIME_STEP()))
  {
    this->Information->CopyEntry(src->Information, DATA_TIME_STEP(), 1);
  }

  // This also caused a pipeline problem.
  // An input pipelineMTime was copied to output.  Pipeline did not execute...
  // We do not copy MTime of object, so why should we copy these.
  // this->PipelineMTime = src->PipelineMTime;
  // this->UpdateTime = src->UpdateTime;
  // this->Locality = src->Locality;

  this->Modified();
}

//------------------------------------------------------------------------------
// This should be a pure virtual method.
void vtkDataObject::Crop(const int*) {}

//------------------------------------------------------------------------------
vtkDataObject* vtkDataObject::GetData(vtkInformation* info)
{
  return info ? info->Get(DATA_OBJECT()) : nullptr;
}

//------------------------------------------------------------------------------
vtkDataObject* vtkDataObject::GetData(vtkInformationVector* v, int i)
{
  return vtkDataObject::GetData(v->GetInformationObject(i));
}

//------------------------------------------------------------------------------
const char* vtkDataObject::GetAssociationTypeAsString(int associationType)
{
  if (associationType < 0 || associationType >= NUMBER_OF_ASSOCIATIONS)
  {
    vtkGenericWarningMacro("Bad association type.");
    return nullptr;
  }
  return FieldAssociationsNames[associationType];
}

//------------------------------------------------------------------------------
int vtkDataObject::GetAssociationTypeFromString(const char* associationName)
{
  if (!associationName)
  {
    vtkGenericWarningMacro("nullptr association name.");
    return -1;
  }

  // check for the name in the FieldAssociations enum
  for (int i = 0; i < NUMBER_OF_ASSOCIATIONS; i++)
  {
    if (!strcmp(associationName, FieldAssociationsNames[i]))
    {
      return i;
    }
  }

  // check for the name in the AttributeTypes enum
  for (int i = 0; i < NUMBER_OF_ATTRIBUTE_TYPES; i++)
  {
    if (!strcmp(associationName, AttributeTypesNames[i]))
    {
      return i;
    }
  }

  vtkGenericWarningMacro("Bad association name \"" << associationName << "\".");
  return -1;
}

//------------------------------------------------------------------------------
vtkDataSetAttributes* vtkDataObject::GetAttributes(int type)
{
  return vtkDataSetAttributes::SafeDownCast(this->GetAttributesAsFieldData(type));
}

//------------------------------------------------------------------------------
vtkUnsignedCharArray* vtkDataObject::GetGhostArray(int type)
{
  vtkFieldData* fieldData = this->GetAttributesAsFieldData(type);
  return fieldData ? vtkArrayDownCast<vtkUnsignedCharArray>(
                       fieldData->GetArray(vtkDataSetAttributes::GhostArrayName()))
                   : nullptr;
}

//------------------------------------------------------------------------------
vtkFieldData* vtkDataObject::GetAttributesAsFieldData(int type)
{
  switch (type)
  {
    case FIELD:
      return this->FieldData;
  }
  return nullptr;
}

//------------------------------------------------------------------------------
int vtkDataObject::GetAttributeTypeForArray(vtkAbstractArray* arr)
{
  for (int i = 0; i < NUMBER_OF_ATTRIBUTE_TYPES; ++i)
  {
    vtkFieldData* data = this->GetAttributesAsFieldData(i);
    if (data)
    {
      for (int j = 0; j < data->GetNumberOfArrays(); ++j)
      {
        if (data->GetAbstractArray(j) == arr)
        {
          return i;
        }
      }
    }
  }
  return -1;
}

//------------------------------------------------------------------------------
vtkIdType vtkDataObject::GetNumberOfElements(int type)
{
  switch (type)
  {
    case FIELD:
      return this->FieldData->GetNumberOfTuples();
  }
  return 0;
}
VTK_ABI_NAMESPACE_END
