/*------------------------------------------------------------------------------*
 * File Name: kgraph.c															*
 * Creation: GRD 2002.08.09														*
 * Purpose: Origin C file														*
 * Copyright (c) OriginLab Corp. 2002, 2003, 2004, 2005, 2006, 2007				*
 * All Rights Reserved															*
 * 																				*
 * Modification Log:															*
 *------------------------------------------------------------------------------*/
 
// Includes
#include <origin.h>
#include "kgraph.h"
#include "$local.h"

////////////////////////////////////////////////////////////////////////////////////

// main
int readkgraph( string filename, string strWksName, uint iInfo = 0 )
{
	file		fid;
	uint		iFileSize = 0;
	uint		iBytesRead = 0;
	ushort		iVersion = 0;	// File version
	char		Buffer[256];	// Generic, used for string reads
	int			iLoop = 0;		// Generic, used for loops
	uint		iPos = 0;		// Generic, used for file position
	int 		iTemp = 0;
	int			iStatus = 0;

	// Globals
	uint		iNumCols = 0;
	uint		iDefColWidth = 0;

	// Constants
	const double	DateOffset1 = 2415018; 	// Dec. 30, 1899
	const double	DateOffset2 = 2416480; 	// Jan. 1, 1904
	const int		Err1 = 1;				// Failed to open file.
	const int		Err2 = 2;				// File too small.
	const int		Err3 = 3;				// Number of Columns inconsistent.
	const int		Err4 = 4;				// Unsupported Data Type.
	const int		Err8 = 8;				// Unsupported version.

	// Begin
	if( fid.Open(filename, file::modeRead) )
	{
		iFileSize = fid.SeekToEnd();

		// If the file is too small to evaluate, just exit
		if(iFileSize<1000)
		{
			iStatus = Err2;
			printf(ORDKG_FILE_TOO_SMALL);	// in LOCAL.H
			fid.Close();
		}
		if(!iStatus)
		{
			fid.SeekToBegin();
			iTemp = fid.ReadInt(&iVersion,2,1,0); // MAC byte order on either PC or MAC
			if(iInfo == 1) printf("%s version %u\n", filename, iVersion);
			iTemp = fid.ReadInt(&iNumCols,2,1,0);
			iTemp = fid.ReadInt(&iDefColWidth,2,1,0);
			if(iNumCols == 0 || iNumCols > 1000) // Stated limit for v3.5.2
			{
				iStatus = 3;
				printf(ORDKG_INCONSISTENT);
				fid.Close();
				return iStatus;
			}
//			printf("Size : %u, Version : %u, Columns : %u, Width : %u\n", iFileSize, iVersion, iNumCols, iDefColWidth);
			fid.Seek(512, file::begin);
			Worksheet	wks(strWksName);
			for( iTemp = wks.GetNumCols(); iTemp < iNumCols; iTemp = wks.GetNumCols() ) wks.AddCol();

			uint	iNumRows = 0;
			uint	iColType = 0;
			uint	iThisCol = 0;
			// Read the Number Of Rows for each column
			for(iThisCol = 0; iThisCol < iNumCols; iThisCol++)
			{
				if(iVersion > 8)
				{
					iTemp = fid.ReadInt(&iNumRows,4,1,0);
				}
				else
				{
					iTemp = fid.ReadInt(&iNumRows,2,1,0);
				}
				wks.SetCell(0,iThisCol,(double) iNumRows);
			}
			// Read the Column Datatype for each column
			for(iThisCol = 0; iThisCol < iNumCols; iThisCol++)
			{
				iTemp = fid.ReadInt(&iColType,2,1,0);
				wks.SetCell(1,iThisCol,(double) iColType);
			}
			// Skip this column name information - Seem to be 'short' in some cases
			fid.Seek(40 * iNumCols, file::current);
			// Now read the data
			uint	iColIndex = 0;
			foreach(Column col in wks.Columns)
			{
				iNumRows = (uint) wks.Cell(0,col.GetIndex());
				iColType = (uint) wks.Cell(1,col.GetIndex());
				Dataset	ds(col);
				ds.SetSize(iNumRows);
				switch(iColType)
				{
				case 0:	// Float
					col.SetFormat(0);	// 0 is Numeric
					kgraph_read_float_data(fid, wks, iColIndex, iNumRows);
					kgraph_read_mask(fid, strWksName, iColIndex, iNumRows);
					break;
				case 1:	// Text
					col.SetFormat(1);	// 1 is Text
					kgraph_read_text_data(fid, wks, iColIndex, iNumRows, iVersion);
					break;
				case 2:	// Date-Time
					col.SetFormat(3);	// 3 is Date
					if(iVersion < 8)
					{
						kgraph_read_float_data(fid, wks, iColIndex, iNumRows);
						// This is days from 1900
						Dataset	ds(wks.Columns(iColIndex));
						ds += DateOffset1;
					}
					else
					{
						kgraph_read_double_data(fid, wks, iColIndex, iNumRows);
						// This is seconds from 1904
						Dataset	ds(wks.Columns(iColIndex));
						ds /= 86400;
						ds += DateOffset2;
					}
					kgraph_read_mask(fid, strWksName, iColIndex, iNumRows);
					break;
				case 3:	// Double (1)
					col.SetFormat(0);	// 0 is Numeric
					kgraph_read_double_data(fid, wks, iColIndex, iNumRows);
					kgraph_read_mask(fid, strWksName, iColIndex, iNumRows);
					break;
				case 4:	// Long (1)
					col.SetFormat(0);	// 0 is Numeric
					kgraph_read_long_data(fid, wks, iColIndex, iNumRows);
					kgraph_read_mask(fid, strWksName, iColIndex, iNumRows);
					break;
				default: // Unknown
					iStatus = Err4;
					printf(ORDKG_UNSUPPORTED_TYPE);
					fid.Close();
					return iStatus;
				}
				kgraph_read_extra(fid, strWksName, iColIndex, iNumRows);
				kgraph_read_name(fid, strWksName, iColIndex, iNumRows);
				iColIndex++;
			}
			LT_execute("wks.labels();");
		}
		fid.Close();
	}
	else
	{
		iStatus = Err1;
		printf(ORDKG_OPEN_FAILED,filename);
		fid.Close();
	}	// end if - opening file
	return iStatus;
	// return iVersion*16+iStatus;
}


// Support functions
int kgraph_read_float_data(file &fid, Worksheet TheWorksheet, uint TheColumn, uint NumRows)
{
	int		iBytesRead = 0;
//	float	fValue = 0;
	Dataset	ds;
	
	vector<float>	vect;
	vect.SetSize(NumRows);
	ds.Attach(TheWorksheet, TheColumn);
	iBytesRead = fid.ReadFloat(vect, SIZE_OF_FLOAT, NumRows, FALSE);
	ds = vect;
//	printf("float\n");
	return 0;
}


int kgraph_read_double_data(file &fid, Worksheet TheWorksheet, uint TheColumn, uint NumRows)
{
	int		iBytesRead = 0;
	Dataset	ds;
	
	vector<double>	vect;
	vect.SetSize(NumRows);
	ds.Attach(TheWorksheet, TheColumn);
	iBytesRead = fid.ReadFloat(vect, SIZE_OF_DOUBLE, NumRows, FALSE);
	ds = vect;
//	printf("double\n");
	return 0;
}


int kgraph_read_long_data(file &fid, Worksheet TheWorksheet, uint TheColumn, uint NumRows)
{
	int		iTemp = 0;
	int		iValue = 0;

	for(int iLoop=0; iLoop < NumRows; iLoop++)
	{
		iTemp = fid.ReadInt(&iValue,4,1,0);		
		TheWorksheet.SetCell(iLoop, TheColumn, (double) iValue);
	}
	return 0;
}


int kgraph_read_text_data(file &fid, Worksheet TheWorksheet, uint TheColumn, uint NumRows, int TheVersion)
{
	char		Buffer[256];
	int			iBytesRead = 0;
	const int	TBLOCKSIZE1 = 21;
	const int	TBLOCKSIZE2 = 51;

	// Skip over descriptive stuff
	fid.Seek(NumRows * 6, file::current);
	// Read text info
	for(int iLoop = 0; iLoop < NumRows; iLoop++)
	{
		if(TheVersion > 11)
		{
			iBytesRead = fid.Read(&Buffer,TBLOCKSIZE2);
		}
		else
		{
			iBytesRead = fid.Read(&Buffer,TBLOCKSIZE1);
		}
		TheWorksheet.SetCell(iLoop, TheColumn, Buffer);
	}
	return 0;
}


void kgraph_read_mask(file &fid, string strWksName, uint TheColumn, uint NumRows)
{
	uint		iMask;
	int			iTemp;

	for(int iLoop = 0; iLoop < NumRows; iLoop++)
	{
		iTemp = fid.ReadInt(&iMask,2,1,0);
		// This information is not used yet
	}
}


void kgraph_read_extra(file &fid, string strWksName, uint TheColumn, uint NumRows)
{
	Extra		Hdr;

	Worksheet	wks(strWksName);

	fid.Read(&Hdr, sizeof(Hdr));
	wks.Columns(TheColumn).SetWidth(Hdr.ColWidth);
	if(wks.Columns(TheColumn).GetFormat() == 3)
	{
		if(Hdr.BitFlags & 4)
		{
			wks.Columns(TheColumn).SetFormat(2);
			wks.Columns(TheColumn).SetSubFormat(3);	// For now
		}
		else
		{
			wks.Columns(TheColumn).SetSubFormat(1);	// For now
		}
	}
}


void kgraph_read_name(file &fid, string strWksName, uint TheColumn, uint NumRows)
{
	char		Buffer[128];
	int			iBytesRead = 0;
	Worksheet	wks(strWksName);

	// Names can be read elsewhere, but they seem shortened in some cases,
	// so I'll read them here
	iBytesRead = fid.Read(&Buffer,128);
	wks.Columns(TheColumn).SetLabel(Buffer);
}


// The filter function version
int ImportKaleidaGraph(Page& pgTarget, TreeNode& trFilter, LPCSTR lpcszFile, int nFile)
{
	string	strName;

	if(pgTarget.GetType() == EXIST_WKS)
	{
		pgTarget.GetName(strName);
	}
	else
	{
		WorksheetPage	pg;
		pg.Create("origin.otp");
		pg.GetName(strName);
	}
	LT_set_str("%B",strName);
	LT_execute("win -a %B;");
	return readkgraph(lpcszFile, strName, 0);
}
