#include "XPathHelper.h"
#include "VTable.h"
#include "global.h"

#include <iostream>
using namespace std;

// function definitions
void printVTable(VTable &v);
void printResource(Resource &r);
void printFieldAttributes(Field &f, int fieldNum);
void printTableData(TableData &td, vector<Field> &fieldList);
void printLinkAttributes(Link &l, int linkNum);
void printValue(Values &v, int valueNum);
void printRange(Range &r);
void printOption(Option &o, int optionNum);
void printInfoAttributes(Info &f, int fieldNum);
void printParamAttributes(Param &f, int fieldNum);
void printCoosysAttributes(Coosys &f, int fieldNum);
void testVTable(const char*	argv[]);
void testResource(const char* argv[]);



/*
* This is a test program to test the VOTable API.
*/

int
main(
			int				argc,
			const char*		argv[])
{
	
	if (argc != 3)
	{
		cout << "Usage TestVOTableAPI xmlfilepath xpath" << endl;
		return 0;
	}

	//testVTable(argv);
	testResource(argv);
	
	cout << endl << "Completed operation - exiting now." << endl;

	return 0;
}

void testVTable(const char*	argv[])
{
	int status;
	
	VTable v;
	
	v.openFile(argv[1], argv[2], 0,  &status);
	cout << endl << "Output of Test Program starts here *****************" << endl;
	cout << "Status of TABLE openFile is  " << status << endl;

	if (status == VOERROR)
	{
		cout << "TABLE could not be opened properly." << endl;
		cout << "Exiting now." << endl;
		return ;
	}
	printVTable(v);
	
	v.closeFile (&status);

}

void testResource(const char*	argv[])
{
	int status;
	
	Resource r;
	
	r.openFile(argv[1], argv[2], 0,  &status);
	cout << endl << "Output of Test Program starts here *****************" << endl;
	cout << "Status of RESOURCE openFile is  " << status << endl;

	if (status == VOERROR)
	{
		cout << "RESOURCE could not be opened properly." << endl;
		cout << "Exiting now." << endl;
		return ;
	}
	printResource(r);
	
	r.closeFile (&status);
}

void printResource(Resource &r)
{
	char * str;
	int status;

	r.getDescription(str, &status);
	if (status == SUCCESS)
	{
		cout << "Resource description is " << str << endl;
		delete[] str;
	}

	r.getID(str, &status);
	if (status == SUCCESS)
	{
		cout << "Resource ID is " << str << endl;
		delete[] str;
	}

	r.getName(str, &status);
	if (status == SUCCESS)
	{
		cout << "Resource name is " << str << endl;
		delete[] str;
	}

	r.getValue(str, &status);
	if (status == SUCCESS)
	{
		cout << "Resource value is " << str << endl;
		delete[] str;
	}

	// test INFO
	int nInfos = 0;
	if (r.getNumOfInfos(nInfos, &status) == SUCCESS && nInfos > 0)
	{
		Info info;
		for (int i = 0; i < nInfos; i++)
		{
			if (r.getInfo (info,i,&status) == SUCCESS)
			{
				printInfoAttributes(info, i + 1);
			}
		}
	}

	// test Coosys
	int nCS = 0;
	if (r.getNumOfCoosys(nCS, &status) == SUCCESS && nCS > 0)
	{
		Coosys c;
		for (int i = 0; i < nCS; i++)
		{
			if (r.getCoosys (c,i,&status) == SUCCESS)
			{
				printCoosysAttributes(c, i + 1);
			}
		}
	}

	// test Params
	int nParams = 0;
	if (r.getNumOfParams(nParams, &status) == SUCCESS && nParams > 0)
	{
		Param p;
		for (int i = 0; i < nParams; i++)
		{
			if (r.getParam (p, i, &status) == SUCCESS)
			{
				printParamAttributes(p, i + 1);
			}
		}
	}

	int nLinks = 0;
	if (r.getNumOfLinks(nLinks, &status) == SUCCESS && nLinks > 0)
	{
		Link l;
		for (int i = 0; i < nLinks; i++)
		{
			if (r.getLink (l,i,&status) == SUCCESS)
			{
				printLinkAttributes(l, i + 1);

			}
		}
	}

	// test VTables
	int nTables = 0;
	if (r.getNumOfTables(nTables, &status) == SUCCESS && nTables > 0)
	{
		VTable v;
		for (int i = 0; i < nTables; i++)
		{
			if (r.getTable (v, i, &status) == SUCCESS)
			{
				cout << "VTable " << (i+1) << endl;
				printVTable(v);
			}
		}
	}

	int nRes = 0;
	if (r.getNumOfResources(nRes, &status) == SUCCESS && nRes > 0)
	{
		Resource res;
		for (int i = 0; i < nRes; i++)
		{
			if (r.getResource (res,i,&status) == SUCCESS)
			{
				cout << "RESOURCE " << (i+1) << endl;
				printResource(res);

			}
		}
	}

	return;

}

void printVTable(VTable &v)
{
	char * str;
	int status;

	v.getName(str, &status);
	if (status == SUCCESS)
	{
		cout << "VTable name is " << str << endl;
		delete[] str;
	}

	v.getID(str, &status);
	if (status == SUCCESS)
	{
		cout << "VTable ID is " << str << endl;
		delete[] str;
	}

	v.getRef(str, &status);
	if (status == SUCCESS)
	{
		cout << "VTable ref is " << str << endl;
		delete[] str;
	}

	TableMetaData tmd;
	TableData td;

	if (v.getMetaData(tmd, &status) == SUCCESS)
	{
		tmd.getDescription(str, &status);
		if (status == SUCCESS)
		{
			cout << "VTable description is " << str << endl;
			delete[] str;
		}

		int numOfCols = 0;
		int numOfLinks = 0;

		tmd.getNumOfColumns(numOfCols, &status);
		tmd.getNumOfLinks(numOfLinks, &status);

		cout << "Number of fields is " << numOfCols << endl;
		cout << "Number of links is " << numOfLinks << endl;

		if (0 == numOfCols)
		{
			cout << "Number of columns is zero, therefore exiting." << endl;
		}

		vector <Field> fieldList;

		for (int i = 0; i < numOfCols; i++)
		{
			Field f;
		
			tmd.getField(f, i, &status);

			printFieldAttributes(f, i + 1);
			fieldList.push_back (f);

		} // end of 'for'

		if (v.getData(td, &status) == SUCCESS)
		{
			printTableData(td, fieldList);
		
		} // end of 'if'
	}
	return;

}

void printInfoAttributes(Info &i, int infoNum)
{
	char * str;
	int status = 0;

	if (i.getID(str, &status) == SUCCESS)
	{
		cout << "Info " << infoNum << " ID is = " << str << endl;
		delete[] str;
	}

	if (i.getValue(str, &status) == SUCCESS)
	{
		cout << "Info " << infoNum << " value is = " << str << endl;
		delete[] str;
	}

	if (i.getName(str, &status) == SUCCESS)
	{
		cout << "Info " << infoNum << " name is = " << str << endl;
		delete[] str;
	}

	if (i.getPCData(str, &status) == SUCCESS)
	{
		cout << "Info " << infoNum << " pcdata is = " << str << endl;
		delete[] str;
	}

}

void printCoosysAttributes(Coosys &c, int cNum)
{
	char * str;
	int status = 0;

	if (c.getID(str, &status) == SUCCESS)
	{
		cout << "Coosys " << cNum << " ID is = " << str << endl;
		delete[] str;
	}

	if (c.getEquinox(str, &status) == SUCCESS)
	{
		cout << "Coosys " << cNum << " equinox is = " << str << endl;
		delete[] str;
	}

	if (c.getEpoch(str, &status) == SUCCESS)
	{
		cout << "Coosys " << cNum << " epoch is = " << str << endl;
		delete[] str;
	}

	if (c.getPCData(str, &status) == SUCCESS)
	{
		cout << "Coosys " << cNum << " pcdata is = " << str << endl;
		delete[] str;
	}

	coosys_system cs;
	if (c.getSystem(cs, &status) == SUCCESS)
	{
		cout << "Coosys " << cNum << " system is = " << cs << endl;
	}
	return;


}

void printParamAttributes(Param &f, int fieldNum)
{
	char * str;
	field_datatype dt;
	int status = 0;
	
	
	if (f.getID(str, &status) == SUCCESS)
	{
		cout << "Param " << fieldNum << " ID is = " << str << endl;
		delete[] str;
	}

	if (f.getName(str, &status) == SUCCESS)
	{
		cout << "Param " << fieldNum << " name is = " << str << endl;
		delete[] str;
	}

	if (f.getUCD(str, &status) == SUCCESS)
	{
		cout << "Param " << fieldNum << " UCD  is = " << str << endl;
		delete[] str;
	}

	if (f.getDatatype(dt, &status) == SUCCESS)
	{
		cout << "Param " << fieldNum << " datatype is = " << dt << endl;

	}

	if (f.getArraySize(str, &status) == SUCCESS)
	{
		cout << "Param " << fieldNum << " arraysize is = " << str << endl;
		delete[] str;
	}

	if (f.getRef(str, &status) == SUCCESS)
	{
		cout << "Param " << fieldNum << " reference is = " << str << endl;
		delete[] str;
	}

	if (f.getUnit(str, &status) == SUCCESS)
	{
		cout << "Param " << fieldNum << " unit is = " << str << endl;
		delete[] str;
	}

	if (f.getPrecision(str, &status) == SUCCESS)
	{
		cout << "Param " << fieldNum << " precision is = " << str << endl;
		delete[] str;
	}

	int width;

	if (f.getWidth(width, &status) == SUCCESS)
	{
		cout << "Param " << fieldNum << " width is = " << width << endl;
	}

	if (f.getDescription (str, &status) == SUCCESS)
	{
		cout << "Param " << fieldNum << " description is = " << str << endl;
		delete[] str;
	}

	if (f.getValue (str, &status) == SUCCESS)
	{
		cout << "Param " << fieldNum << " value is = " << str << endl;
		delete[] str;
	}

	bool b;
	if (f.isVariableType(b, &status) == SUCCESS && b == true)
	{
		cout << "Param " << fieldNum << " is of variable length." << endl;
	}

	int nLinks = 0;
	if (f.getNumOfLinks(nLinks, &status) == SUCCESS && nLinks > 0)
	{
		Link l;
		for (int i = 0; i < nLinks; i++)
		{
			if (f.getLink (l,i,&status) == SUCCESS)
			{
				printLinkAttributes(l, i + 1);

			}
		}
	}
	int numOfValues = 0;


	if (f.getNumOfValues(numOfValues, &status) == SUCCESS && numOfValues > 0)
	{
		for (int i = 0; i < numOfValues; i++)
		{
			Values v;
			if (f.getValues (v, i, &status) == SUCCESS)
			{
				printValue(v, i + 1);
			}
		}
	}

	return;

}


void printFieldAttributes(Field &f, int fieldNum)
{
	char * str;
	field_datatype dt;
	int status = 0;
	
	
	if (f.getID(str, &status) == SUCCESS)
	{
		cout << "Field " << fieldNum << " ID is = " << str << endl;
		delete[] str;
	}

	if (f.getName(str, &status) == SUCCESS)
	{
		cout << "Field " << fieldNum << " name is = " << str << endl;
		delete[] str;
	}

	if (f.getUCD(str, &status) == SUCCESS)
	{
		cout << "Field " << fieldNum << " UCD  is = " << str << endl;
		delete[] str;
	}

	if (f.getDatatype(dt, &status) == SUCCESS)
	{
		cout << "Field " << fieldNum << " datatype is = " << dt << endl;

	}

	field_type t;
	if (f.getType(t, &status) == SUCCESS)
	{
		cout << "Field " << fieldNum << " type is = " << t << endl;

	}

	if (f.getArraySize(str, &status) == SUCCESS)
	{
		cout << "Field " << fieldNum << " arraysize is = " << str << endl;
		delete[] str;
	}

	if (f.getRef(str, &status) == SUCCESS)
	{
		cout << "Field " << fieldNum << " reference is = " << str << endl;
		delete[] str;
	}

	if (f.getUnit(str, &status) == SUCCESS)
	{
		cout << "Field " << fieldNum << " unit is = " << str << endl;
		delete[] str;
	}

	if (f.getPrecision(str, &status) == SUCCESS)
	{
		cout << "Field " << fieldNum << " precision is = " << str << endl;
		delete[] str;
	}

	int width;

	if (f.getWidth(width, &status) == SUCCESS)
	{
		cout << "Field " << fieldNum << " width is = " << width << endl;
	}

	if (f.getDescription (str, &status) == SUCCESS)
	{
		cout << "Field " << fieldNum << " description is = " << str << endl;
		delete[] str;
	}

	bool b;
	if (f.isVariableType(b, &status) == SUCCESS && b == true)
	{
		cout << "Field " << fieldNum << " is of variable length." << endl;
	}

	int nLinks = 0;
	if (f.getNumOfLinks(nLinks, &status) == SUCCESS && nLinks > 0)
	{
		Link l;
		for (int i = 0; i < nLinks; i++)
		{
			if (f.getLink (l,i,&status) == SUCCESS)
			{
				printLinkAttributes(l, i + 1);

			}
		}
	}
	int numOfValues = 0;


	if (f.getNumOfValues(numOfValues, &status) == SUCCESS && numOfValues > 0)
	{
		for (int i = 0; i < numOfValues; i++)
		{
			Values v;
			if (f.getValues (v, i, &status) == SUCCESS)
			{
				printValue(v, i + 1);
			}
		}
	}

}

void printValue(Values &v, int valueNum)
{

	char * str;
	int status = 0;

	if (v.getID(str, &status) == SUCCESS)
	{
		cout << "Value " << valueNum << " ID is = " << str << endl;
		delete[] str;
	}

	if (v.getNull(str, &status) == SUCCESS)
	{
		cout << "Value " << valueNum << " null is = " << str << endl;
		delete[] str;
	}

	values_type t;
	if (v.getType(t, &status) == SUCCESS)
	{
		cout << "Value " << valueNum << " type is = " << t << endl;
	}

	bool b;
	if (v.isValid(b, &status) == SUCCESS)
	{
		cout << "Value " << valueNum << " invalid is = " << b << endl;
	}

	Range *r;
	
	if (v.getMinimun(r, &status) == SUCCESS)
	{
		printRange(*r);
		delete r;
	}

	if (v.getMaximum(r, &status) == SUCCESS)
	{
		printRange(*r);
		delete r;
	}

	Option o;
	int numOfOptions = 0;
	if (v.getNumOfOptions(numOfOptions, &status) == SUCCESS)
	{
		for (int i = 0; i < numOfOptions; i ++)
		{

			if (v.getOption(o, i, &status) == SUCCESS)
			{
				printOption(o, i + 1);
			}
		}
	}

	return;

}

void printRange(Range &r)
{
	char * str;
	int status = 0;

	if (r.getValue(str, &status) == SUCCESS)
	{
		cout << "Range value is = " << str << endl;
		delete[] str;

	}

	bool b;

	if (r.isInclusive(b, &status) == SUCCESS)
	{
		cout << "Range inclusive is = " << b << endl;

	}

}

void printOption(Option &o, int optionNum)
{

int getOption(Option &option, int index, int *status);
int getNumOfOption(int &numOfOptions, int *status);

	char *str;
	int status = 0;

	if(o.getName (str, &status) == SUCCESS)
	{
		cout << "Option " << optionNum << " name is = " << str << endl;
		delete[] str;
	}

	if(o.getValue (str, &status) == SUCCESS)
	{
		cout << "Option " << optionNum << " value is = " << str << endl;
		delete[] str;
	}

	int numOfOptions = 0;

	// get Option and print
	//if(o.getNumOfOption
}

void printTableData(TableData &td, vector<Field> &fieldList)
{
	int numOfRows = 0;
	int status = 0;

	if (td.getNumOfRows(numOfRows, &status) == SUCCESS)
	{
		cout << "Number of rows in this table data are " << numOfRows << endl;
	}
	field_datatype dt;

	// get each row
	for (int rowIndex = 0; rowIndex < numOfRows; rowIndex++)
	{
		Row r;
		if (td.getRow(r, rowIndex, &status) == SUCCESS)
		{
			// get each column of row and print it.
			
			Column c;
			
			for (int colIndex = 0; colIndex < fieldList.size (); colIndex++)
			{
				Field field = fieldList[colIndex];
				int numOfElements = 0;
				if (field.getDatatype (dt, &status) == SUCCESS)
				{
					if (r.getColumn (c, colIndex, &status) == SUCCESS)
					{
						cout << endl << endl << "*** Row " << rowIndex + 1 << " Col " 
							<< (colIndex + 1) << " ***";
						switch (dt) {
						case IntType :
							{
								int *intArray;
								if (c.getIntArray(intArray, numOfElements, &status) == SUCCESS)
								{
									cout << endl << "Number of elements is " << numOfElements << endl;
									cout << "Data is " ;
									for (int i = 0; i < numOfElements; i ++)
									{
										 cout << intArray[i] << " ";
									}
									
									delete[] intArray;
								}
								break;
							}
						case ShortType :
						{
							short *shortArray;
							if (c.getShortArray(shortArray, numOfElements, &status) == SUCCESS)
							{
								cout << endl << "Number of elements is " << numOfElements << endl;
								cout << "Data is " ;
								for (int i = 0; i < numOfElements; i ++)
								{
									 cout << shortArray[i] << " ";
								}
								delete[] shortArray;
							}
							break;
						}
						case FloatType :
							{
								float *floatArray;
								if (c.getFloatArray(floatArray, numOfElements, &status) == SUCCESS)
								{
									cout << endl << "Number of elements is " << numOfElements << endl;
									cout << "Data is " ;
									for (int i = 0; i < numOfElements; i ++)
									{
										 cout << floatArray[i] << " ";
									}
									delete[] floatArray;
								}
								break;
							}
						case CharType :
							{
								char *charArray;
								if (c.getCharArray(charArray, numOfElements, &status) == SUCCESS)
								{
									cout << endl << "Number of elements is " << numOfElements << endl;
									cout << "Data is =>" ;
									for (int i = 0; i < numOfElements; i ++)
									{
										 cout << charArray[i] << " ";
									}
									cout << "<=" << endl;
									delete[] charArray;
								}
								break;
							}
						default : { cout << "Unknown Datatype !" << endl; break; }
						} // switch


						} // if
				}

			} // end of 'for'

		}
	}


}


void printLinkAttributes(Link &l, int linkNum)
{
	char * str;
	int status = 0;

	if (l.getID(str, &status) == SUCCESS)
	{
		cout << "Link " << linkNum << " ID is " << str << endl;
		delete[] str;
	}

	if (l.getHRef(str, &status) == SUCCESS)
	{
		cout << "Link " << linkNum << " HRef is " << str << endl;
		delete[] str;
	}

	if (l.getTitle(str, &status) == SUCCESS)
	{
		cout << "Link " << linkNum << " title is " << str << endl;
		delete[] str;
	}

	if (l.getGRef(str, &status) == SUCCESS)
	{
		cout << "Link " << linkNum << " GRef is " << str << endl;
		delete[] str;
	}

	if (l.getAction(str, &status) == SUCCESS)
	{
		cout << "Link " << linkNum << " action is " << str << endl;
		delete[] str;
	}

	if (l.getPCData(str, &status) == SUCCESS)
	{
		cout << "Link " << linkNum << " pcdata is " << str << endl;
		delete[] str;
	}

	if (l.getContentType(str, &status) == SUCCESS)
	{
		cout << "Link " << linkNum << " content type is " << str << endl;
		delete[] str;
	}

	if (l.getValue(str, &status) == SUCCESS)
	{
		cout << "Link " << linkNum << " value is " << str << endl;
		delete[] str;
	}

	content_role c;
	if (l.getContentRole(c, &status) == SUCCESS)
	{
		cout << "Link " << linkNum << " content role is " << c << endl;
		
	}


}