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

  Copyright (c) Kitware, Inc.
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/VolViewCopyright.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 "vtkVVDataItemVolumeContourCollection.h"

#include "vtkObjectFactory.h"
#include "vtkCollection.h"
#include "vtkSmartPointer.h"
#include "vtkVVDataItemVolume.h"
#include "vtkVVDataItemVolumeContour.h"
#include "vtkGarbageCollector.h"

//---------------------------------------------------------------------------
// Set of default colors. In so far as possible, when we add a new contour to
// a data-item, a new unique (or least used) default color is picked for you 
// automagically. 
double vtkVVDataItemVolumeContourCollectionDefaultColors[][3] = 
{
  { 0.4, 1.0, 0.4 },
  { 1.0, 0.4, 0.4 }, 
  { 0.4, 0.4, 1.0 },
  { 1.0, 0.0, 0.4 },
  { 1.0, 0.4, 1.0 },
  { 0.4, 1.0, 1.0 },
  { 1.0, 0.2, 0.5 },
  { 0.3, 0.7, 0.0 },
  { 0.5, 0.2, 1.0 },
  { 1.0, 0.5, 0.0 },
  { 0.0, 1.0, 0.0 },
  { 0.0, 0.0, 1.0 },
  { 1.0, 0.2, 0.8 },
  { 0.2, 1.0, 0.8 },
  { 0.2, 0.4, 0.8 },
  { 0.9, 0.5, 0.2 },
  { 0.4, 0.9, 0.2 },
  { 0.5, 0.2, 0.9 },
  { 0.7, 0.3, 0.9 },
  { 0.9, 0.3, 0.5 },
  { 0.3, 0.9, 1.0 },
};

//---------------------------------------------------------------------------
vtkCxxRevisionMacro(vtkVVDataItemVolumeContourCollection, "$Revision: 1.10 $");
vtkStandardNewMacro(vtkVVDataItemVolumeContourCollection);

//---------------------------------------------------------------------------
vtkVVDataItemVolumeContourCollection::vtkVVDataItemVolumeContourCollection()
{
  this->Collection = vtkCollection::New();
  this->DataItemVolume = NULL;
}

//---------------------------------------------------------------------------
vtkVVDataItemVolumeContourCollection::~vtkVVDataItemVolumeContourCollection()
{
  this->SetDataItemVolume(NULL);
  this->Collection->Delete();
}

//---------------------------------------------------------------------------
vtkVVDataItemVolumeContour * vtkVVDataItemVolumeContourCollection::AddNewItem()
{
  vtkSmartPointer< vtkVVDataItemVolumeContour > c 
    = vtkSmartPointer< vtkVVDataItemVolumeContour >::New();

  // Randomly pick a color
  c->SetColor(vtkVVDataItemVolumeContourCollectionDefaultColors[rand() % 20]);

  this->AddItem( c );
  return c;
}

//---------------------------------------------------------------------------
// Add an object to the list. Prevents duplicate entries.
void vtkVVDataItemVolumeContourCollection::AddItem( vtkVVDataItemVolumeContour *a )
{
  if (!this->IsItemPresent(a))
    {
    a->SetDataItemVolume(this->DataItemVolume);
    this->Collection->AddItem(a);
    }
}

//---------------------------------------------------------------------------
void vtkVVDataItemVolumeContourCollection::RemoveItem( vtkVVDataItemVolumeContour *a )
{
  this->Collection->RemoveItem(a);
}

//---------------------------------------------------------------------------
void vtkVVDataItemVolumeContourCollection::RemoveAllItems()
{
  this->Collection->RemoveAllItems();
}

//---------------------------------------------------------------------------
int vtkVVDataItemVolumeContourCollection::IsItemPresent( vtkVVDataItemVolumeContour *a )
{
  return this->Collection->IsItemPresent(a);
}

//---------------------------------------------------------------------------
int vtkVVDataItemVolumeContourCollection::GetNumberOfItems()
{
  return this->Collection->GetNumberOfItems();
}

//---------------------------------------------------------------------------
vtkVVDataItemVolumeContour *
vtkVVDataItemVolumeContourCollection::GetNthItem(int i)
{
  return vtkVVDataItemVolumeContour::SafeDownCast( 
            this->Collection->GetItemAsObject(i) );
}

//---------------------------------------------------------------------------
// Remove the i'th item in the list.
void vtkVVDataItemVolumeContourCollection::RemoveItem(int i)
{
  this->Collection->RemoveItem(i);
}

//---------------------------------------------------------------------------
void vtkVVDataItemVolumeContourCollection
::SetDataItemVolume( vtkVVDataItemVolume *v )
{
  vtkSetObjectBodyMacro( DataItemVolume, vtkVVDataItemVolume, v );

  // Propagate to all items on this list.
  const int n = this->GetNumberOfItems();
  for (int i = 0; i < n; i++)
    {
    this->GetNthItem(i)->SetDataItemVolume(v);
    }
}

//---------------------------------------------------------------------------
int vtkVVDataItemVolumeContourCollection
::GetNumberOfContoursWithDescription( const char *description )
{
  int retVal = 0;
  const int n = this->GetNumberOfItems();
  for (int i = 0; i < n; i++)
    {
    const char *contourDescription = this->GetNthItem(i)->GetDescription();
    if (contourDescription == NULL && description == NULL)
      {
      ++retVal;
      }
    else if (contourDescription && description)
      {
      std::string contourDescriptionString = contourDescription;
      std::string descriptionString = description;
      retVal += (contourDescriptionString.compare(descriptionString) == 0 ? 1 : 0);
      }
    }  
  return retVal;
}

//----------------------------------------------------------------------------
vtkVVDataItemVolumeContour * vtkVVDataItemVolumeContourCollection
::GetNthContourWithDescription( int k, const char *description )
{
  int nthContourWithDescription = 0;
  const int n = this->GetNumberOfItems();
  for (int i = 0; i < n; i++)
    {
    vtkVVDataItemVolumeContour *contour = this->GetNthItem(i);
    const char *contourDescription = contour->GetDescription();

    bool isEqual = false;
    
    if (contourDescription == NULL && description == NULL)
      {
      isEqual = true;
      }
    else if (contourDescription && description)
      {
      std::string contourDescriptionString = contourDescription;
      std::string descriptionString = description;
      isEqual = (contourDescriptionString.compare(descriptionString) == 0);
      }

    if (isEqual)
      {
      if (nthContourWithDescription == k)
        {
        return contour;
        }
      ++nthContourWithDescription;
      }

    }    

  return NULL;
}

//----------------------------------------------------------------------------
// Determine the modified time of this object
unsigned long vtkVVDataItemVolumeContourCollection::GetMTime()
{
  unsigned long result = 0;

  // Get the max of all contours in the collection.
  vtkVVDataItemVolumeContour *a;
  vtkCollectionSimpleIterator ait;
  for ( this->Collection->InitTraversal(ait); 
          (a=static_cast< vtkVVDataItemVolumeContour * >(
            this->Collection->GetNextItemAsObject(ait))); )
    {
    unsigned long t = a->GetMTime();
    if (t > result) { result = t; }
    }

  // Check the collection itself for changes.
  unsigned long mtime = this->Collection->GetMTime();
  result = ( mtime > result ? mtime : result);  
  
  // Finally check ourselves.
  mtime = vtkObject::GetMTime();
  result = ( mtime > result ? mtime : result);  

  return result;
}

//----------------------------------------------------------------------
void vtkVVDataItemVolumeContourCollection::Register( vtkObjectBase *o )
{
  this->RegisterInternal(o, 1);
}

//----------------------------------------------------------------------
void vtkVVDataItemVolumeContourCollection::UnRegister( vtkObjectBase *o )
{
  this->UnRegisterInternal(o, 1);
}

//----------------------------------------------------------------------
void vtkVVDataItemVolumeContourCollection::ReportReferences(vtkGarbageCollector* collector)
{
  this->Superclass::ReportReferences(collector);
  vtkGarbageCollectorReport(collector, this->DataItemVolume, "DataItemVolume");    
}

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

