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

  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 "vtkImageStencilDataFlip.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkObjectFactory.h"
#include "vtkStreamingDemandDrivenPipeline.h"
#include "vtkImageStencilData.h"

vtkCxxRevisionMacro(vtkImageStencilDataFlip, "$Revision: 1.4 $");
vtkStandardNewMacro(vtkImageStencilDataFlip);

vtkImageStencilDataFlip::vtkImageStencilDataFlip()
{
  this->FlipExtent[0] = 0;  
  this->FlipExtent[1] = 0;  
  this->FlipExtent[2] = 0;  
  this->FlipExtent[3] = 0;  
  this->FlipExtent[4] = 0;  
  this->FlipExtent[5] = 0;  
}

vtkImageStencilDataFlip::~vtkImageStencilDataFlip()
{
}

//----------------------------------------------------------------------------
void vtkImageStencilDataFlip::SetInput(vtkImageStencilData *input)
{
  if (input)
    {
    this->SetInputConnection(0, input->GetProducerPort());
    }
  else
    {
    this->SetInputConnection(0, 0);
    }
}

//----------------------------------------------------------------------------
vtkImageStencilData *vtkImageStencilDataFlip::GetInput()
{
  if (this->GetNumberOfInputConnections(0) < 1)
    {
    return NULL;
    }
  
  return vtkImageStencilData::SafeDownCast(
    this->GetExecutive()->GetInputData(0, 0));
}

//----------------------------------------------------------------------------
int vtkImageStencilDataFlip::RequestData(
  vtkInformation *request,
  vtkInformationVector **inputVector,
  vtkInformationVector *outputVector)
{
  this->Superclass::RequestData(request, inputVector, outputVector);

  vtkInformation *inInfo = inputVector[0]->GetInformationObject(0);
  vtkInformation *outInfo = outputVector->GetInformationObject(0);

  vtkImageStencilData *input = vtkImageStencilData::SafeDownCast(
    inInfo->Get(vtkDataObject::DATA_OBJECT()));
  vtkImageStencilData *output = vtkImageStencilData::SafeDownCast(
    outInfo->Get(vtkDataObject::DATA_OBJECT()));

  // Allocate output 
  // Get the extents w.r.t which we will derive complimentary extents.
  int extent[6];
  if ( this->FlipExtent[0]==0 && this->FlipExtent[1]==0 && this->FlipExtent[2]==0
    && this->FlipExtent[3]==0 && this->FlipExtent[4]==0 && this->FlipExtent[5]==0 )
    {
    input->GetExtent( extent ); // Get Extent from input
    }
  else
    {
    this->GetFlipExtent( extent ); // User set the extents
    }
  output->SetExtent( extent );
  output->AllocateExtents();
  
  // Flip the stencil data. Note that the vtkImageStencilData assumes that the
  // end points returned by GetNextExtent are included in the stencil. So the
  // flip must exclude them.
  //
  int iter=0, idxZ, idxY;
  for (idxZ = extent[4]; idxZ <= extent[5]; idxZ++)
    {
    for (idxY = extent[2]; idxY <= extent[3]; idxY++, iter=0)
      {
      // For each scan line
      int r1, r2, r2prev, moreSubExtents = 1;
      unsigned int numberOfSubExtents = 0;
      
      while( moreSubExtents )
        {
        moreSubExtents = input->GetNextExtent( 
            r1, r2, extent[0], extent[1], idxY, idxZ, iter);
        
        ++numberOfSubExtents; // nth subextent on this scan line.
        
        if (r1 > r2 && !moreSubExtents && numberOfSubExtents == 1)
          {
          // Bogus data.. discard. If there are no extents in the line, 
          // vtkImageStencilData returns moreSubExtents = 0 and r1 = r2+1
          // The complimentary extent is the whole line
          //std::cout << "InsertNextExtent " << extent[0] << " " << extent[1] << " " << idxY << " " << idxZ << std::endl;
          output->InsertNextExtent( extent[0], extent[1], idxY, idxZ );
          break;
          }
          
        if (numberOfSubExtents == 1 && r1 > extent[0])
          {
          // This is the first extent we received and there was a gap between
          // this and the left boundary.
          // Add the region from the left boundary to r1 for this scan line
          //std::cout << "InsertNextExtent " << extent[0] << " " << r1-1 << " " << idxY << " " << idxZ << std::endl;
          output->InsertNextExtent(extent[0], r1 -1 , idxY, idxZ);
          }
        else if (r1 > extent[0] && numberOfSubExtents > 1 && r2 >= r1 && r2 <= extent[1])
          {
          // This is not the first extent we received. Add the region from the end
          // of the previous to the begin of this one.
          int r1new = r1 -1;
          if (r2prev <= r1new)
            {
            //std::cout << "InsertNextExtent " << r2prev << " " << r1new << " " << idxY << " " << idxZ << std::endl;
            output->InsertNextExtent(r2prev, r1new, idxY, idxZ);
            }
          }
        
        if (r2 < extent[1] && moreSubExtents == 0)
          {
          // This is the last available extent. Add the region from the end of 
          // this to the right boundary (if such a region exists)
          //std::cout << "InsertNextExtent " << r2 + 1 << " " << extent[1] << " " << idxY << " " << idxZ << std::endl;
          output->InsertNextExtent(r2+1, extent[1], idxY, idxZ);
          }
        
        if ((r1 == r2+1) && moreSubExtents == 0 && numberOfSubExtents > 1 && r2prev <= extent[1])
          {
          // The last extent was the last available extent. Add the region from 
          // the end of its to the right boundary (if such a region exists)
          //std::cout << "InsertNextExtent " << r2prev << " " << extent[1] << " " << idxY << " " << idxZ << std::endl;
          output->InsertNextExtent(r2prev, extent[1], idxY, idxZ);
          break;
          }
        
        r2prev = r2 + 1;
        
        }
      }
    }

  return 1;
}

//----------------------------------------------------------------------------
int vtkImageStencilDataFlip::FillInputPortInformation(int,vtkInformation* info)
{
  info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkImageStencilData");
  return 1;
}

//----------------------------------------------------------------------------
int vtkImageStencilDataFlip::RequestInformation(
  vtkInformation *,
  vtkInformationVector **,
  vtkInformationVector *outputVector)
{
  vtkInformation *outInfo = outputVector->GetInformationObject(0);
  int extent[6];
  if ( this->FlipExtent[0]==0 && this->FlipExtent[1]==0 && this->FlipExtent[2]==0
    && this->FlipExtent[3]==0 && this->FlipExtent[4]==0 && this->FlipExtent[5]==0 )
    {
    this->GetInput()->GetExtent( extent ); // Get Extent from input
    }
  else
    {
    this->GetFlipExtent( extent ); // User set the extents
    }
  
  outInfo->Set(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(), extent, 6);
  this->GetOutput()->SetSpacing( this->GetInput()->GetSpacing() );
  this->GetOutput()->SetOrigin(  this->GetInput()->GetOrigin() );
  return 1;
}

//----------------------------------------------------------------------------
// This method computes the Region of input necessary to generate outRegion.
int vtkImageStencilDataFlip::RequestUpdateExtent (
  vtkInformation * vtkNotUsed(request),
  vtkInformationVector **inputVector,
  vtkInformationVector *outputVector)
{
  // get the info objects
  vtkInformation *inInfo = inputVector[0]->GetInformationObject(0);
  vtkImageStencilData *input = vtkImageStencilData::SafeDownCast(
    inInfo->Get(vtkDataObject::DATA_OBJECT()));
  
  int inExt[6];
  input->GetExtent( inExt );
  inInfo->Set(vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT(), inExt, 6);

  return 1;
}

//----------------------------------------------------------------------------
void vtkImageStencilDataFlip::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);
  os << indent << "FlipExtent: (" << this->FlipExtent[0];
  for (int idx = 1; idx < 6; ++idx)
    {
    os << ", " << this->FlipExtent[idx];
    }
  os << ")\n";
}

