#include "vtkJHTDBReader.h"
#include <string.h>
#include <vtkDataObject.h>
#include <vtkFloatArray.h>
#include <vtkImageData.h>
#include <vtkInformation.h>
#include <vtkInformationVector.h>
#include <vtkPointData.h>
#include <vtkSmartPointer.h>
#include <vtkStreamingDemandDrivenPipeline.h>

#using <System.dll>
#using <System.Data.dll>

using namespace System;
using namespace System::Collections::Generic;
using namespace System::Text;
using namespace System::Data;
using namespace System::Data::SqlClient;
using namespace System::Collections;

vtkJHTDBReader* vtkJHTDBReader::New()
{
	return new vtkJHTDBReader();
}

vtkJHTDBReader::vtkJHTDBReader()
{
	this->dataPointSize = sizeof(float);
	this->atomSize = 4;
	this->SqlArrayHeaderSize = 24;
	this->components = 3;
	this->FileName = NULL;
	this->SetNumberOfInputPorts(0);
	this->extent[0] = 0;
	this->extent[1] = 16;
	this->extent[2] = 0;
	this->extent[3] = 16;
	this->extent[4] = 0;
	this->extent[5] = 16;
}

vtkJHTDBReader::~vtkJHTDBReader()
{
	delete [] this->FileName;
}

void vtkJHTDBReader::SetFileName(const char* fname)
{
	size_t size = strlen(fname) + 1;
	this->FileName = new char[size];
    strcpy_s(this->FileName, size, fname);
}

const char* vtkJHTDBReader::GetFileName()
{
	return this->FileName;
}

void vtkJHTDBReader::PrintSelf(ostream& os, vtkIndent indent)
{
	this->Superclass::PrintSelf(os,indent);
	
	os << indent << "File Name: " 
		<< (this->FileName ? this->FileName : "(none)") << "\n";
}

int vtkJHTDBReader::RequestInformation (
	vtkInformation*,
	vtkInformationVector**,
	vtkInformationVector* outputVector)
{
	vtkInformation* outInfo =
		outputVector->GetInformationObject(0);

	double spacing[3] = {1, 1, 1};
	double origin[3] = {0, 0, 0};

	outInfo->Set(
		vtkStreamingDemandDrivenPipeline::
		WHOLE_EXTENT(),
		this->extent, 6);
	outInfo->Set(vtkDataObject::SPACING(),spacing, 3);
	outInfo->Set(vtkDataObject::ORIGIN(), origin, 3);
	vtkDataObject::SetPointDataActiveScalarInfo(outInfo, VTK_FLOAT, 1);

	return 1;
}

int vtkJHTDBReader::RequestData(
	vtkInformation*,
	vtkInformationVector**,
	vtkInformationVector* outputVector)
{
	//int extent[6];

	vtkImageData* image =
		vtkImageData::GetData(outputVector);

	//TODO: How to change the extent?
	//image->GetExtent(extent);

	String^ cString = "server=localhost;database=turbdev;Integrated Security=true;";
    SqlConnection ^ sqlcon = gcnew SqlConnection(cString);
    sqlcon->Open();
	if (sqlcon->State == ConnectionState::Open)
		cerr << "JHTDBReader: connected to database" << endl;
	else
		cerr << "JHTDBReader: error connecting to database " << endl;

	String^ queryBox = String::Format("box[{0},{1},{2},{3},{4},{5}]", extent[0], extent[2], extent[4], extent[1], extent[3], extent[5]);
	SqlCommand ^ command = gcnew SqlCommand();
	command->Connection = sqlcon;
	command->CommandType = CommandType::StoredProcedure;
	command->CommandText = "GetDataCutout";
	command->Parameters->Add(gcnew SqlParameter("@serverName",SqlDbType::VarChar));
	command->Parameters["@serverName"]->Value = "localhost";
	command->Parameters->Add(gcnew SqlParameter("@dbname",SqlDbType::VarChar));
	command->Parameters["@dbname"]->Value = "turbarrayQ";
	command->Parameters->Add(gcnew SqlParameter("@codedb",SqlDbType::VarChar));
	command->Parameters["@codedb"]->Value = "turbdev";
	command->Parameters->Add(gcnew SqlParameter("@dataset",SqlDbType::VarChar));
	command->Parameters["@dataset"]->Value = "vel_08";
	command->Parameters->Add(gcnew SqlParameter("@blobDim",SqlDbType::Int));
	command->Parameters["@blobDim"]->Value = 8;
	command->Parameters->Add(gcnew SqlParameter("@timestep",SqlDbType::Int));
	command->Parameters["@timestep"]->Value = 4000;
	command->Parameters->Add(gcnew SqlParameter("@queryBox",SqlDbType::VarChar));
	command->Parameters["@queryBox"]->Value = queryBox;

	SqlDataReader ^ reader = command->ExecuteReader();

	int x_width = (extent[1] - extent[0]);
	int y_width = (extent[3] - extent[2]);
	int z_width = (extent[5] - extent[4]);
	int data_size = x_width * y_width * z_width * components * dataPointSize;
	array<unsigned char>^ rawdata = gcnew array<unsigned char>(data_size);

	__int64 bytesRead = 0;
	int bufferIndex = 0;
	while (reader->Read())
	{
		bufferIndex = (int)bytesRead;
		bytesRead += reader->GetBytes(0, 0, rawdata, bufferIndex, data_size - bufferIndex);
	}
	reader->Close();

	image->SetDimensions(x_width, y_width, z_width);
	image->AllocateScalars(VTK_FLOAT, 1);

	vtkDataArray* scalars =
		image->GetPointData()->GetScalars();

	scalars->SetName("Scalar Data");
	for (vtkIdType z = 0; z < z_width; ++z)
	{
		for (vtkIdType y = 0; y < y_width; ++y)
		{
			for (vtkIdType x = 0; x < x_width; ++x)
			{
				int offset = z * y_width * x_width + y * x_width + x;
				float value = BitConverter::ToSingle(rawdata, offset * components * dataPointSize);
				scalars->SetTuple1(offset, value);
			}
		}
	}

	delete rawdata;

	sqlcon->Close();

	return 1;
}
