//=========================================================================
//  Copyright (c) Kitware, Inc.
//  All rights reserved.
//  See LICENSE.txt 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 "vtkModelLineSource.h"

#include "vtkCellArray.h"
#include "vtkFloatArray.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkObjectFactory.h"
#include "vtkPointData.h"
#include "vtkPoints.h"
#include "vtkPolyData.h"
#include "vtkStreamingDemandDrivenPipeline.h"

#include <math.h>
vtkStandardNewMacro(vtkModelLineSource);

vtkModelLineSource::vtkModelLineSource(int res)
{
  this->Point1[0] = -0.5;
  this->Point1[1] = 0.0;
  this->Point1[2] = 0.0;

  this->Point2[0] = 0.5;
  this->Point2[1] = 0.0;
  this->Point2[2] = 0.0;

  this->Resolution = (res < 1 ? 1 : res);
  this->BuildVertex = 1;
  this->SetNumberOfInputPorts(0);
}

int vtkModelLineSource::RequestInformation(vtkInformation* vtkNotUsed(request),
  vtkInformationVector** vtkNotUsed(inputVector), vtkInformationVector* outputVector)
{
  // get the info object
  vtkInformation* outInfo = outputVector->GetInformationObject(0);
  outInfo->Set(CAN_HANDLE_PIECE_REQUEST(), 1);
  return 1;
}

int vtkModelLineSource::RequestData(vtkInformation* vtkNotUsed(request),
  vtkInformationVector** vtkNotUsed(inputVector), vtkInformationVector* outputVector)
{
  // get the info object
  vtkInformation* outInfo = outputVector->GetInformationObject(0);

  // get the ouptut
  vtkPolyData* output = vtkPolyData::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT()));

  int numLines = this->Resolution;
  int numPts = this->Resolution + 1;
  double x[3], tc[3], v[3];
  int i, j;
  vtkPoints* newPoints;
  vtkFloatArray* newTCoords;
  vtkCellArray* newLines;

  if (outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_PIECE_NUMBER()) > 0)
  {
    return 1;
  }

  newPoints = vtkPoints::New();
  newPoints->Allocate(numPts);
  newTCoords = vtkFloatArray::New();
  newTCoords->SetNumberOfComponents(2);
  newTCoords->Allocate(2 * numPts);
  newTCoords->SetName("Texture Coordinates");
  newLines = vtkCellArray::New();
  newLines->Allocate(newLines->EstimateSize(numLines, 2));
  //
  // Generate points and texture coordinates
  //
  for (i = 0; i < 3; i++)
  {
    v[i] = this->Point2[i] - this->Point1[i];
  }

  tc[1] = 0.0;
  tc[2] = 0.0;
  for (i = 0; i < numPts; i++)
  {
    tc[0] = (static_cast<double>(i) / this->Resolution);
    for (j = 0; j < 3; j++)
    {
      x[j] = this->Point1[j] + tc[0] * v[j];
    }
    newPoints->InsertPoint(i, x);
    newTCoords->InsertTuple(i, tc);
  }
  //
  //  Generate lines
  //
  newLines->InsertNextCell(numPts);
  for (i = 0; i < numPts; i++)
  {
    newLines->InsertCellPoint(i);
  }

  //  Generate vertex if BuildVertex is set to true
  //
  if (this->BuildVertex)
  {
    vtkCellArray* Verts = vtkCellArray::New();
    Verts->Allocate(numPts);
    for (i = 0; i < numPts; i++)
    {
      vtkIdType PointId = i;
      Verts->InsertNextCell(1, &PointId);
    }
    output->SetVerts(Verts);
    Verts->Delete();
  }

  //
  // Update ourselves and release memory
  //
  output->SetPoints(newPoints);
  newPoints->Delete();

  output->GetPointData()->SetTCoords(newTCoords);
  newTCoords->Delete();

  output->SetLines(newLines);
  newLines->Delete();

  return 1;
}

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

  os << indent << "Resolution: " << this->Resolution << "\n";

  os << indent << "Point 1: (" << this->Point1[0] << ", " << this->Point1[1] << ", "
     << this->Point1[2] << ")\n";

  os << indent << "Point 2: (" << this->Point2[0] << ", " << this->Point2[1] << ", "
     << this->Point2[2] << ")\n";
}
