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

  Program:   CMB
  Module:    pqCMBSceneNodeIterator.cxx

  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.

=========================================================================*/
// .NAME pqCMBSceneNodeIterator - iterates over a Scene Sub-Tree.
// .SECTION Description
// .SECTION Caveats



#include "pqCMBSceneNodeIterator.h"
#include "pqCMBSceneNode.h"
#include "pqCMBGlyphObject.h"
#include "pqCMBFacetedObject.h"

pqCMBSceneNodeIterator::pqCMBSceneNodeIterator(pqCMBSceneNode *root)
{
  this->Root = root;
  this->reset();
}

pqCMBSceneNodeIterator::~pqCMBSceneNodeIterator()
{
}

void pqCMBSceneNodeIterator::reset()
{
  while (!this->Stack.empty())
    {
    this->Stack.pop();
    }
  this->Stack.push(Root);
}

void pqCMBSceneNodeIterator::addChildren(pqCMBSceneNode *node)
{
  int n = node->getChildren().size();
  int i;
  pqCMBSceneNode *child;
  for (i = n-1; i >= 0; i--)
    {
    child = node->getChildren()[i];
    if (!child->isMarkedForDeletion())
        {
        this->Stack.push(child);
        }
    }
}

pqCMBSceneNode *pqCMBSceneNodeIterator::next()
{
  if (this->Stack.empty())
    {
    return NULL;
    }

  pqCMBSceneNode *node = this->Stack.top();
  this->Stack.pop();
  this->addChildren(node);
  return node;
}

SceneObjectNodeIterator::SceneObjectNodeIterator(pqCMBSceneNode *root) :
  pqCMBSceneNodeIterator(root), NoTypeSet(true),
  NoSurfaceTypeSet(true), FilterSurfaceType(pqCMBSceneObjectBase::Other)
{
  this->FilterTypes.insert(pqCMBSceneObjectBase::Unknown);
}

SceneObjectNodeIterator::~SceneObjectNodeIterator()
{
}

pqCMBSceneNode *SceneObjectNodeIterator::next()
{
  pqCMBSceneNode *node;
  while ((node = pqCMBSceneNodeIterator::next()))
    {
    if (node->isMarkedForDeletion())
        {
        continue;
        }
    if (node->getDataObject())
      {
      if (this->NoTypeSet)
        {
        return node;
        }
      if  (this->FilterTypes.count(node->getDataObject()->getType()))
        {
        if (this->NoSurfaceTypeSet)
          {
          return node;
          }
        if (node->getDataObject()->getType() == pqCMBSceneObjectBase::Faceted)
          {
          if (dynamic_cast<pqCMBFacetedObject *>
              (node->getDataObject())->getSurfaceType() == this->FilterSurfaceType)
            {
            return node;
            }
          }
        else if (node->getDataObject()->getType() == pqCMBSceneObjectBase::Glyph)
          {
          if (dynamic_cast<pqCMBGlyphObject *>
              (node->getDataObject())->getSurfaceType() == this->FilterSurfaceType)
            {
            return node;
            }
          }
       }
      }
    }
  return NULL;
}

void SceneObjectNodeIterator::setTypeFilter(pqCMBSceneObjectBase::enumObjectType objectType)
{
  this->NoTypeSet = false;
  this->NoSurfaceTypeSet = true;
  this->FilterTypes.clear();
  this->FilterTypes.insert(objectType);
}

void SceneObjectNodeIterator::addObjectTypeFilter(pqCMBSceneObjectBase::enumObjectType objectType)
{
  this->NoTypeSet = false;
  this->NoSurfaceTypeSet = true;
  this->FilterTypes.insert(objectType);
}

void SceneObjectNodeIterator::setTypeFilter(pqCMBSceneObjectBase::enumObjectType objectType,
                                            pqCMBSceneObjectBase::enumSurfaceType surfaceType)
{
  this->NoTypeSet = false;
  this->NoSurfaceTypeSet = false;
  this->FilterTypes.clear();
  this->FilterTypes.insert(objectType);
  this->FilterSurfaceType = surfaceType;
}

void SceneObjectNodeIterator::clearTypeFilter()
{
  this->NoTypeSet = true;
  this->NoSurfaceTypeSet = true;
}
