#ifndef vtkCTHDataArray_h
#define vtkCTHDataArray_h

// #include "vtksnlIOWin32Header.h"

#include "vtkDataArray.h"
#include "vtkDoubleArray.h"

class VTK_EXPORT vtkCTHDataArray : public vtkDataArray
{
public:
  static vtkCTHDataArray *New ();
  vtkTypeMacro(vtkCTHDataArray, vtkDataArray);
  void PrintSelf (ostream& os, vtkIndent indent);

  // Description:
  // Prepares for new data
  void Initialize ();

  // Description:
  // Get the data type
  int GetDataType ()
    { return VTK_DOUBLE; }

  int GetDataTypeSize () { return static_cast<int>(sizeof(double)); }

  // Description:
  // Return the size, in bytes, of the lowest-level element of an
  // array.  For vtkDataArray and subclasses this is the size of the
  // data type.
  virtual int GetElementComponentSize()
    { return this->GetDataTypeSize(); }

  // Description:
  // Set the dimensions the data will be contained within
  void SetDimensions (int x, int y, int z);
  void SetDimensions (int *x)
    { this->SetDimensions (x[0], x[1], x[2]); }
  const int* GetDimensions ()
    { return this->Dimensions; }

  // Description:
  // Sets the extent over which the data is valid.
  // This is because with CTH cells can extend one past the boundary,
  // so we must skip over the data associated with those and consequently
  // act externally (as a vtkDataArray) as though our dimensions are one less.
  void SetExtents (int x0, int x1, int y0, int y1, int z0, int z1);
  void SetExtents (int* lo, int *hi)
    { this->SetExtents (lo[0], hi[0], lo[1], hi[1], lo[2], hi[2]); }
  void SetExtent (int* x)
    { this->SetExtents (x[0], x[1], x[2], x[3], x[4], x[5]); }
  int *GetExtents ()
    { return this->Extents; }
  void UnsetExtents ();

  // Description:
  // Set the data pointers from the CTH code
  void SetDataPointer (int comp, int k, int j, double *istrip);

  // Description:
  // Copy the tuple value into a user-provided array.
  void GetTuple (vtkIdType i, double* tuple);
  double *GetTuple (vtkIdType i);

  // Description:
  // Returns an ArrayIterator over doubles, this will end up with a deep copy
  vtkArrayIterator* NewIterator ();

  vtkIdType LookupValue (vtkVariant value);
  void LookupValue (vtkVariant value, vtkIdList* ids);
  void SetVariantValue (vtkIdType vtkNotUsed(index), vtkVariant vtkNotUsed(value)) { /* TODO */ }

  // Description:
  // Get the address of a particular data index. Performs no checks
  // to verify that the memory has been allocated etc.
  double* GetPointer(vtkIdType id);
  void* GetVoidPointer(vtkIdType id) { return this->GetPointer (id); }
  void ExportToVoidPointer(void *out_ptr);

  int Allocate (vtkIdType sz, vtkIdType ext=1000)
  {
    BuildFallback ();
    return Fallback->Allocate (sz, ext);
  }

  void SetNumberOfComponents (int number)
  {
    this->Superclass::SetNumberOfComponents (number);
    if (this->Fallback)
      {
      this->Fallback->SetNumberOfComponents (this->GetNumberOfComponents ());
      }
  }

  void SetNumberOfTuples (vtkIdType number)
  {
    this->BuildFallback ();
    this->Fallback->SetNumberOfTuples (number);
    this->Size = this->Fallback->GetSize ();
    this->MaxId = this->Fallback->GetMaxId ();
  }

  // Description:
  // A number of abstract functions from the super class that must not be called
  void SetTuple(vtkIdType i, vtkIdType j, vtkAbstractArray* aa)
  {
    this->BuildFallback ();
    this->Fallback->SetTuple (i, j, aa);
  }
  void SetTuple(vtkIdType i, const float *f)
  {
    this->BuildFallback ();
    this->Fallback->SetTuple (i, f);
  }
  void SetTuple(vtkIdType i, const double *d)
  {
    this->BuildFallback ();
    this->Fallback->SetTuple (i, d);
  }

  void InsertTuple(vtkIdType i, vtkIdType j, vtkAbstractArray* aa)
  {
    this->BuildFallback ();
    this->Fallback->InsertTuple (i, j, aa);
  }
  void InsertTuple (vtkIdType i, const float *f)
  {
    this->BuildFallback ();
    this->Fallback->InsertTuple (i, f);
  }
  void InsertTuple (vtkIdType i, const double *d)
  {
    this->BuildFallback ();
    this->Fallback->InsertTuple (i, d);
  }
  void InsertTuples(vtkIdList *dstIds, vtkIdList *srcIds,
                    vtkAbstractArray* source)
  {
    this->BuildFallback();
    this->Fallback->InsertTuples(dstIds, srcIds, source);
  }
  virtual void InsertTuples(vtkIdType dstStart, vtkIdType n, vtkIdType srcStart,
                            vtkAbstractArray* source)
  {
    this->BuildFallback();
    this->Fallback->InsertTuples(dstStart, n, srcStart, source);
  }

  vtkIdType InsertNextTuple(vtkIdType i, vtkAbstractArray* aa)
  {
    this->BuildFallback ();
    vtkIdType ret = this->Fallback->InsertNextTuple (i, aa);
    this->Size = this->Fallback->GetSize ();
    this->MaxId = this->Fallback->GetMaxId ();
    return ret;
  }
  vtkIdType InsertNextTuple(const float *f)
  {
    this->BuildFallback ();
    vtkIdType ret = this->Fallback->InsertNextTuple (f);
    this->Size = this->Fallback->GetSize ();
    this->MaxId = this->Fallback->GetMaxId ();
    return ret;
  }
  vtkIdType InsertNextTuple(const double *d)
  {
    this->BuildFallback ();
    vtkIdType ret = this->Fallback->InsertNextTuple (d);
    this->Size = this->Fallback->GetSize ();
    this->MaxId = this->Fallback->GetMaxId ();
    return ret;
  }

  void InsertVariantValue (vtkIdType idx, vtkVariant value)
  {
    this->BuildFallback ();
    return this->Fallback->InsertVariantValue (idx, value);
  }

  void RemoveTuple (vtkIdType id)
  {
    this->BuildFallback ();
    this->Fallback->RemoveTuple (id);
  }
  void RemoveFirstTuple ()
  {
    this->BuildFallback ();
    this->Fallback->RemoveFirstTuple ();
  }
  void RemoveLastTuple ()
  {
    this->BuildFallback ();
    this->Fallback->RemoveLastTuple ();
  }

  void* WriteVoidPointer (vtkIdType i, vtkIdType j)
  {
    this->BuildFallback ();
    return this->Fallback->WriteVoidPointer (i, j);
  }

  virtual void DeepCopy (vtkAbstractArray* aa)
  {
    this->BuildFallback ();
    return this->Fallback->DeepCopy (aa);
  }

  virtual void DeepCopy(vtkDataArray *da)
  {
    return this->DeepCopy( (vtkAbstractArray*) da);
  }

  void SetVoidArray (void *p, vtkIdType id, int i, int j)
  {
    this->BuildFallback ();
    return this->Fallback->SetVoidArray (p, id, i, j);
  }
  void SetVoidArray (void *p, vtkIdType id, int i)
  {
    this->BuildFallback ();
    return this->Fallback->SetVoidArray (p, id, i);
  }

  // Description:
  // Since we don't allocate, this does nothing
  // unless we're already falling back
  void Squeeze ()
  {
    if (this->Fallback)
      {
      this->Size = this->Fallback->GetSize ();
      this->MaxId = this->Fallback->GetMaxId ();
      this->Fallback->Squeeze ();
      }
  }

  // Description:
  int Resize (vtkIdType numTuples)
  {
    this->BuildFallback ();
    return this->Fallback->Resize (numTuples);
  }

  void DataChanged ()
  {
    this->BuildFallback ();
    return this->Fallback->DataChanged ();
  }

  void ClearLookup ()
  {
    this->BuildFallback ();
    return this->Fallback->ClearLookup ();
  }
protected:
  vtkCTHDataArray ();
  ~vtkCTHDataArray ();

  int Dimensions[3];

  bool ExtentsSet;
  int Extents[6];
  int Dx;
  int Dy;
  int Dz;

  vtkMTimeType PointerTime;

  double ***Data;
  double *CopiedData;
  int CopiedSize;
  double *Tuple;
  int TupleSize;

  void BuildFallback ();
  // A writeable version of this array, delegated.
  vtkDoubleArray *Fallback;
private:
  vtkCTHDataArray (const vtkCTHDataArray&) VTK_DELETE_FUNCTION;
  void operator= (const vtkCTHDataArray&) VTK_DELETE_FUNCTION;
};

#endif /* vtkCTHDataArray_h */
