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

  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 "vtkRECISTCalculator.h"

#include "vtkObjectFactory.h"
#include "vtkCell.h"
#include "vtkDataObject.h"
#include "vtkIdList.h"
#include "vtkMath.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkExecutive.h"
#include "vtkSmartPointer.h"
#include "vtkCutter.h"
#include "vtkImageData.h"
#include "vtkPlane.h"
#include "vtkStreamingDemandDrivenPipeline.h"
#include "vtkPoints.h"

vtkStandardNewMacro(vtkRECISTCalculator);

#define  VTK_CUBE_ROOT(x) \
  ((x<0.0)?(-pow((-x),0.333333333333333)):(pow((x),0.333333333333333)))

//----------------------------------------------------------------------------
// Constructs with initial 0 values.
vtkRECISTCalculator::vtkRECISTCalculator()
{
  this->RECISTMeasure = 0.0;

  this->SetNumberOfInputPorts(2);
  this->SetNumberOfOutputPorts(0);
}

//----------------------------------------------------------------------------
vtkRECISTCalculator::~vtkRECISTCalculator()
{
}

//----------------------------------------------------------------------------
void vtkRECISTCalculator::SetImageData(vtkImageData *s)
{
  this->SetInput(1, s); 
}

//----------------------------------------------------------------------------
vtkImageData *vtkRECISTCalculator::GetImageData()
{
  if (this->GetNumberOfInputConnections(1) < 1) 
    { 
    return NULL;
    }
  return vtkImageData::SafeDownCast(
    this->GetExecutive()->GetInputData(1, 0));
}

//----------------------------------------------------------------------------
int vtkRECISTCalculator::FillInputPortInformation(int port, vtkInformation *info)
{
  if (port == 0)
    {
    info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkPolyData");
    }
  else
    {
    info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkImageData");
    }
  return 1;
}

//----------------------------------------------------------------------------
// Description:
// This method measures RECIST value
int vtkRECISTCalculator::RequestData(
  vtkInformation* vtkNotUsed( request ),
  vtkInformationVector** inputVector,
  vtkInformationVector* vtkNotUsed( outputVector ))
{
  vtkInformation *inInfo =
    inputVector[0]->GetInformationObject(0);

  // call ExecuteData
  vtkPolyData *input = vtkPolyData::SafeDownCast(
    inInfo->Get(vtkDataObject::DATA_OBJECT()));

  vtkImageData *image = this->GetImageData();

  int extents[6];
  double origin[3], spacing[3], polydataBounds[6], planeOrigin[3];
  image->GetExtent(extents);
  image->GetOrigin(origin);
  image->GetSpacing(spacing);
  input->GetBounds(polydataBounds);

  vtkSmartPointer< vtkCutter > cutter 
    = vtkSmartPointer< vtkCutter >::New();
  cutter->SetInput(input);

  vtkSmartPointer< vtkPlane > plane = vtkSmartPointer< vtkPlane >::New();
  cutter->SetCutFunction(plane);
  plane->SetNormal(0,0,1.0);

  planeOrigin[0] = polydataBounds[0];
  planeOrigin[1] = polydataBounds[2];
  double cutPolyBounds[6];

  double recist = 0, d, p1[3], p2[3];
  for (int e = extents[4]; e <= extents[5]; e++)
    {
    const double z = (double)e * spacing[2] + origin[2];
    if (z < polydataBounds[4] || z > polydataBounds[5])
      {
      continue;
      }

    planeOrigin[2] = z;
    plane->SetOrigin(planeOrigin);
    cutter->Update();

    vtkPolyData *cutPoly = cutter->GetOutput();
    vtkPoints *cutPoints = cutPoly->GetPoints();
    const int nPoints = cutPoly->GetNumberOfPoints();
    cutPoly->GetBounds(cutPolyBounds);
    const double maxPossible =
     (cutPolyBounds[0] - cutPolyBounds[1])* 
     (cutPolyBounds[0] - cutPolyBounds[1]) +
     (cutPolyBounds[2] - cutPolyBounds[3])* 
     (cutPolyBounds[2] - cutPolyBounds[3]);
    if (maxPossible < recist)
      {
      continue;
      }

    for (int i = 0; i < (nPoints-1); i++)
      {
      cutPoints->GetPoint(i, p1);
      for (int j = i; j < nPoints; j++)
        {
        cutPoints->GetPoint(j, p2);
        }
      d = vtkMath::Distance2BetweenPoints(p1,p2);
      if (d > recist)
        {
        recist = d;
        }
      }
    }


  this->RECISTMeasure = sqrt(recist);

  return 1;
}

//---------------------------------------------------------------------------
int vtkRECISTCalculator::RequestUpdateExtent(
  vtkInformation *vtkNotUsed(request),
  vtkInformationVector **inputVector,
  vtkInformationVector *outputVector)
{
  vtkInformation* outInfo = outputVector->GetInformationObject(0);
  vtkInformation *inInfo0 = inputVector[0]->GetInformationObject(0);
  vtkInformation *inInfo1 = inputVector[1]->GetInformationObject(0);
  vtkPolyData *inData0 = vtkPolyData::SafeDownCast(
    inInfo0->Get(vtkDataObject::DATA_OBJECT()));
  vtkImageData *inData1 = vtkImageData::SafeDownCast(
    inInfo1->Get(vtkDataObject::DATA_OBJECT()));

  int *inWextent = inInfo1->Get(
      vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT());
  inInfo1->Set(vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT(), 
      inWextent, 6);

  return 1;
}

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

  vtkPolyData *input = vtkPolyData::SafeDownCast(this->GetInput(0));
  if (!input)
    {
    return;
    }
}

