#include "vtkStructuredGridGenerator.h"

#include <vtkObjectFactory.h>
#include <vtkStructuredGrid.h>
#include <vtkInformation.h>
#include <vtkInformationVector.h>
#include <vtkSmartPointer.h>
#include <vtkStreamingDemandDrivenPipeline.h>
#include <vtkPoints.h>

#define VTK_CREATE(type, name) \
  vtkSmartPointer<type> name = vtkSmartPointer<type>::New()

vtkCxxRevisionMacro(vtkStructuredGridGenerator, "$Revision: 0.1 $");
vtkStandardNewMacro(vtkStructuredGridGenerator);

vtkStructuredGridGenerator::vtkStructuredGridGenerator()
{
    this->SetNumberOfInputPorts(0);

    this->IRange[0] = -1.0;
    this->IRange[1] = 1.0;
    this->JRange[0] = -1.0;
    this->JRange[1] = 1.0;
    this->KRange[0] = -1.0;
    this->KRange[1] = 1.0;

    this->Dimensions[0] = 2;
    this->Dimensions[1] = 2;
    this->Dimensions[2] = 2;
}

vtkStructuredGridGenerator::~vtkStructuredGridGenerator()
{
}

int vtkStructuredGridGenerator::RequestInformation(
    vtkInformation *vtkNotUsed(request),
    vtkInformationVector **vtkNotUsed(inputVector),
    vtkInformationVector *outputVector)
{
    vtkInformation *outInfo = outputVector->GetInformationObject(0);

    int wholeExtent[6];
    wholeExtent[0] = 0;   wholeExtent[1] = this->Dimensions[0] - 1;
    wholeExtent[2] = 0;   wholeExtent[3] = this->Dimensions[1] - 1;
    wholeExtent[4] = 0;   wholeExtent[5] = this->Dimensions[2] - 1;

    outInfo->Set(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(),
                 wholeExtent, 6);
    return 1;
}

int vtkStructuredGridGenerator::RequestData(
    vtkInformation* vtkNotUsed(request),
    vtkInformationVector** inputVector,
    vtkInformationVector* outputVector)
{
    vtkInformation* outInfo = outputVector->GetInformationObject(0);
    vtkStructuredGrid* output = vtkStructuredGrid::SafeDownCast(
                                    outInfo->Get(vtkDataObject::DATA_OBJECT()));
    if (!output)
    {
        vtkDebugMacro( << "Invalid output");
        return 0;
    }

    int extent[6];
    outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT(), extent);
    output->SetExtent(extent);

    double steps[3];
    steps[0] = (this->IRange[1] - this->IRange[0])
               / static_cast<double>(this->Dimensions[0] - 1);
    steps[1] = (this->JRange[1] - this->JRange[0])
               / static_cast<double>(this->Dimensions[1] - 1);
    steps[2] = (this->KRange[1] - this->KRange[0])
               / static_cast<double>(this->Dimensions[2] - 1);

    VTK_CREATE(vtkPoints, points);

    points->Allocate((extent[1] - extent[0] + 1)
                     * (extent[3] - extent[2] + 1)
                     * (extent[5] - extent[4] + 1));

    for (int k = extent[4]; k <= extent[5]; ++k)
        for (int j = extent[2]; j <= extent[3]; ++j)
            for (int i = extent[0]; i <= extent[1]; ++i)
            {
                double p[3];

                p[0] = IRange[0] + (steps[0] * static_cast<double>(i));
                p[1] = JRange[0] + (steps[1] * static_cast<double>(j));
                p[2] = KRange[0] + (steps[2] * static_cast<double>(k));

                points->InsertNextPoint(p);
            }

    output->SetPoints(points);

    return 1;
}

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

