#include <maya/MStatus.h>
#include <stdio.h>
#include <math.h>
#include <string>

#include "TableReader.h"

void getLine( FILE *f, std::string *s )
{
	char c;

	do
	{
		c = fgetc(f);
	} while( (c == '\n' || c == '\r') && !feof(f) );
	
	while( c != '\n' && c != '\r' && !feof(f) )
	{
		*s += c;

		c = fgetc(f);
	}
}

unsigned int readUIntLine( FILE *f )
{
	std::string s;

	getLine( f, &s );

	return strtoul( s.c_str(), NULL, 10 );
}

float readFloatLine( FILE *f )
{
	std::string s;

	getLine( f, &s );

	return (float)strtod( s.c_str(), NULL );
}

void readTableRow( FILE *f, float *tr )
{
	std::string s;

	getLine( f, &s );

	const char *p = s.c_str();
	char *endPtr = 0;

	unsigned int i;
	for(i=0;;i++)
	{
		float val = (float)strtod( p, &endPtr );

		if( p != endPtr )
			tr[i] = val;
		else
			break;

		p = endPtr;

		// Skip the comma
		//
		if( *p == ',' )
			p++;
		else
			break;
	}
}


/* Table format:
 *  format: CSV file, header includes XResolu, YResolu, XBegin, XEnd,
 *  YBegin, YEnd.
 *  
 *  For F table, X corresponds to v, Y corresponds to u as specified
 *  in paper.
 *  
 *  For G table, X corresponds to Tsp, Y corresponds to theta_s as
 *  specified in paper.
 */

TableReader::TableReader()
{
	table = 0;
}

TableReader::~TableReader()
{
	unsigned int i;
	for(i=0;i < yResolution;i++)
		delete[] table[i];

	delete[] table;
}


MStatus TableReader::Load( char *fileName )
{
	FILE *tableFile;
	std::string fullFileName;

	fullFileName += getenv( "SINGLE_SCATTER_PATH" );
	fullFileName += "\\";
	fullFileName += fileName;

	if( !(tableFile = fopen( fullFileName.c_str(), "r" )) )
	{
		cerr << "Can't find table file " << fileName << endl
			 << "Please point the SINGLE_SCATTER_PATH environment variable to the" << endl
			 << "location of the table files" << endl;
		return MStatus::kFailure;
	}

	// Read header
	//
	xResolution = readUIntLine( tableFile );
	yResolution = readUIntLine( tableFile );

	xBegin = readFloatLine( tableFile );
	xEnd = readFloatLine( tableFile );
	yBegin = readFloatLine( tableFile );
	yEnd = readFloatLine( tableFile );

	// Read in table
	//
	table = new float *[yResolution];

	unsigned int i;
	for(i=0;i < yResolution;i++)
	{
		table[i] = new float[xResolution];

		readTableRow( tableFile, table[i] );
	}

	fclose( tableFile );

/*	cerr << xResolution << " " << yResolution << " "
		 << xBegin << " " << yBegin << " "
		 << xEnd << " " << yEnd << endl;*/

	return MStatus::kSuccess;	
}

// Using nearest neighbor for look up
//
float TableReader::LookUp( float x, float y )
{
	// Clamp the x and y values
	//
	if( x < xBegin )
		x = xBegin;
	if( x > xEnd )
		x = xEnd;

	if( y < yBegin )
		y = yBegin;
	if( y > yEnd )
		y = yEnd;

	// Find the nearest neighbors
	//
	unsigned int xRounded, yRounded;
	
	xRounded = (unsigned int)floor( ((x - xBegin) / (xEnd - xBegin)) * (float)(xResolution - 1) + 0.5 );
	yRounded = (unsigned int)floor( ((y - yBegin) / (yEnd - yBegin)) * (float)(yResolution - 1) + 0.5 );
	
	return table[yRounded][xRounded];
}
