// Solution.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "Solution.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// The one and only application object

CWinApp theApp;

using namespace std;

//int main()
//{
//    int nRetCode = 0;
//
//    HMODULE hModule = ::GetModuleHandle(nullptr);
//
//    if (hModule != nullptr)
//    {
//        // initialize MFC and print and error on failure
//        if (!AfxWinInit(hModule, nullptr, ::GetCommandLine(), 0))
//        {
//            // TODO: change error code to suit your needs
//            wprintf(L"Fatal Error: MFC initialization failed\n");
//            nRetCode = 1;
//        }
//        else
//        {
//            // TODO: code your application's behavior here.
//        }
//    }
//    else
//    {
//        // TODO: change error code to suit your needs
//        wprintf(L"Fatal Error: GetModuleHandle failed\n");
//        nRetCode = 1;
//    }
//
//    return nRetCode;
//}


using namespace std;

#include <stdio.h>
#include<iostream>
#include <stdlib.h>
#include <mkl.h>
#include "omp.h"



//#include "DynaFlight.h"

void CalculateEigenValues(CString f1, CString f2);
void ReadOP4Data(CString massMatrixFile, float **&op4Data, int& nRow, int& nCol);
void GetOP4BlockHeaderData(CString headerRow, int *curRow, int *curCol, int *noOfValsInBlock);
//void print2dArray(double* array, CString filename, int noOfRow, int noOfCol, bool bAppend=false);
//void print2dArray(float** array, CString filename, int noOfRow, int noOfCol, bool bAppend = false);
void print2dArray(float* array, CString filename, int noOfRow, int noOfCol, bool bAppend = false);

int main(int argc, CHAR* argv[])
{
	//printf("MAIN");
	
	int nRetCode = 0;
	if (argc >= 2)
	{
		CString f1 = CString(argv[1]);
		CString f2 = CString(argv[2]);

		CalculateEigenValues(f1, f2);
	}
	else
	{
		printf("Please use as:\n %s massMatrix.op4 stiffmatrix.op4", argv[0]);

	}
	Sleep(2000);
	return nRetCode;
}

void CalculateEigenValues(CString f1, CString f2)
{
	float **massData = NULL;
	float **stiffData = NULL;
	int massNoOfRow = 0, massNoOfCol = 0;
	int stiffNoOfRow = 0, stiffNoOfCol = 0;
	ReadOP4Data(f1, massData, massNoOfRow, massNoOfCol);
	ReadOP4Data(f2, stiffData, stiffNoOfRow, stiffNoOfCol);

	float *massData1D = new float[massNoOfRow*massNoOfCol];
	float *stiffData1D = new float[stiffNoOfRow*stiffNoOfCol];

	for (int i = 0; i < massNoOfRow; i++)
	{
		for (int j = 0; j < massNoOfCol; j++)
		{
			massData1D[i*massNoOfRow + j] = massData[i][j];
		}
	}

	for (int i = 0; i < stiffNoOfRow; i++)
	{
		for (int j = 0; j < stiffNoOfCol; j++)
		{
			stiffData1D[i*stiffNoOfRow + j] = stiffData[i][j];
		}
	}

	char chUpLo;
	//if (mscNastranJob.m_isUpperTriangle)
	chUpLo = 'U';
	//else
	//	chUpLo = 'L';
	float *walphar = new float[massNoOfRow];
	float *alphai = new float[massNoOfRow];
	float *beta = new float[massNoOfRow];
	float *vl = new float[massNoOfRow*massNoOfRow];
	float *vr = new float[massNoOfRow*massNoOfRow];
	int iType = 1;
	char jobZ = 'N';

	print2dArray(massData1D, CString("mass.csv"), massNoOfRow, massNoOfCol);
	print2dArray(stiffData1D, CString("stiff.csv"), stiffNoOfRow, stiffNoOfCol);

	int retval;
	//	if (mscNastranJob.m_isSymmetric)
	//{
	//	retval = LAPACKE_ssygv(LAPACK_ROW_MAJOR, iType, jobZ, chUpLo, massNoOfRow, stiffData1D, massNoOfRow, massData1D, stiffNoOfRow, walphar);
	//	print2dArray(walphar, CString("walphar.csv"), massNoOfRow, 1);
	//	printf("Retval : %d \n", retval);
	//	//if (retval == 0)
	//	//{
	//	//	CEigenvaluesOutput outputDlg;
	//	//	outputDlg.SetOmega(walphar, massNoOfRow);
	//	//	outputDlg.DoModal();
	//	//}
	//}
	//else
	//{
		retval = LAPACKE_sggev(LAPACK_ROW_MAJOR, jobZ, jobZ, massNoOfRow, stiffData1D, massNoOfRow, massData1D, stiffNoOfRow, walphar, alphai, beta, vl, massNoOfRow, vr, massNoOfRow);
		float *omega = new float[massNoOfRow];
		if (retval == 0)
		{
			for (int j = 0; j < massNoOfRow; j++)
			{
				omega[j] = (walphar[j]+alphai[j]) / beta[j];
			}
	
		}
		printf("Retval : %d \n", retval);
		print2dArray(omega, CString("omega.csv"), massNoOfRow, 1);


	//		CEigenvaluesOutput outputDlg;
	//		outputDlg.SetOmega(omega, massNoOfRow);
	//		outputDlg.DoModal();
	//	}
}

void ReadOP4Data(CString massMatrixFile, float **&op4Data, int& nRow, int& nCol)
{
	CStdioFile fOp4File;
	CFileException excOp4File;

	if (!fOp4File.Open(massMatrixFile, CFile::modeRead, &excOp4File))
	{
		return;
	}


	CString firstLine;
	CString resToken;
	int curPos = 0;
	fOp4File.ReadString(firstLine);
	resToken = firstLine.Tokenize(_T(" "), curPos);
	int tokenNo = 1;
	int commaPos = 0;
	int ePos = 0;
	int noOfValPerRow = 0;
	while (resToken != _T(""))
	{
		switch (tokenNo)
		{
		case 1:	//no of rows
			nCol = atoi(resToken.GetBuffer(0));
			break;
		case 2:	//no of columns
			nRow = atoi(resToken.GetBuffer(0));
			break;
		case 3:
			break;
		case 4:
			break;
		case 5:	//format for the values
			commaPos = resToken.Find(_T(','));
			ePos = resToken.Find(_T('E'));
			noOfValPerRow = atoi(resToken.Mid(commaPos + 1, ePos - commaPos));
			break;
		default:
			break;
		}

		resToken.ReleaseBuffer();
		resToken = firstLine.Tokenize(_T(" "), curPos);
		tokenNo++;
	}

	//Allocate memory for the data
	if (op4Data == NULL)
	{
		op4Data = new float*[nRow];
		for (int i = 0; i < nRow; i++)
		{
			op4Data[i] = new float[nCol];
			memset(op4Data[i], 0, nCol * sizeof(float));
		}
	}

	int noOfRowPerRecord = 1 + (int)(ceilf((float)nCol / (float)noOfValPerRow));	//1 row for column header
	int recordsRowNo = 0;

	CString strRead;
	CString valToken;
	int curRow = 0, curCol = -1, noOfValsInBlock = 0;

	fOp4File.ReadString(strRead);
	do
	{
		if (recordsRowNo%noOfRowPerRecord == 0)
		{
			//Get the col number, row number and the no of words in the next block from this line ...
			GetOP4BlockHeaderData(strRead, &curRow, &curCol, &noOfValsInBlock);
			//curCol++;
			//curRow = 0;
			curCol = curCol - 1;	//align wrt 0 based array index
			curRow = curRow - 1;	//align wrt 0 based array index
			noOfRowPerRecord = 1 + (int)(ceilf((float)noOfValsInBlock / (float)noOfValPerRow));	//1 row for column header
			recordsRowNo = 1;		//+1 for the column header row			
			continue;
		}
		curPos = 0;
		while (curPos < strRead.GetLength() && curRow < nRow && curCol < nCol)	//(valToken != _T(""))
		{
			valToken = strRead.Mid(curPos, 16);// strRead.Tokenize(_T("+ -"), curPos);
			curPos += 16;
			op4Data[curRow][curCol] = (float)atof(valToken);
			//valToken = strRead.Tokenize(_T(" "), curPos);
			//valToken = strRead.Mid(curPos, 16);
			//curPos += 16;
			curRow++;
		}
		recordsRowNo++;
	} while (fOp4File.ReadString(strRead));
	int x = curRow + curCol;
	fOp4File.Close();
}

void GetOP4BlockHeaderData(CString headerRow, int *curRow, int *curCol, int *noOfValsInBlock)
{
	//Header Row format:     1080     955     126
	int nRowLen = headerRow.GetLength();
	int curPos = 0;
	int curVal = 0;
	while (curPos < nRowLen)
	{
		CString valToken = headerRow.Mid(curPos, 8);// strRead.Tokenize(_T("+ -"), curPos);
		curPos += 8;
		curVal++;
		switch (curVal)
		{
		case 1:
			*curCol = (int)atoi(valToken);
			break;
		case 2:
			*curRow = (int)atoi(valToken);
			break;
		case 3:
			*noOfValsInBlock = (int)atoi(valToken);
			break;
		default:
			break;
		}
	}
}

void print2dArray(float* array, CString filename, int noOfRow, int noOfCol, bool bAppend)
{
	CStdioFile outFile;

	CFileException expFile;
	UINT openFlags = CFile::modeCreate | CFile::modeWrite;
	if (bAppend)
		openFlags |= CFile::modeNoTruncate;

	if (!outFile.Open(filename, openFlags, &expFile))
	{
		AfxMessageBox("Failed to create file ...");
		return;
	}
	else
	{
		outFile.SeekToEnd();
		CString strLine;
		for (int i = 0; i < noOfRow; i++)
		{
			for (int j = 0; j < noOfCol; j++)
			{
				CString strTemp = "";
				strTemp.Format("%16.9g, ", array[i*noOfCol + j]);
				strLine += strTemp;
			}
			strLine.TrimRight(',');
			outFile.WriteString(strLine);
			outFile.WriteString("\n");
			strLine.Empty();
		}
		outFile.Close();
	}
}

void print2dArray(float** array, CString filename, int noOfRow, int noOfCol, bool bAppend)
{
	CStdioFile outFile;

	CFileException expFile;
	UINT openFlags = CFile::modeCreate | CFile::modeWrite;
	if (bAppend)
		openFlags |= CFile::modeNoTruncate;

	if (!outFile.Open(filename, openFlags, &expFile))
	{
		AfxMessageBox("Failed to create file ...");
		return;
	}
	else
	{
		outFile.SeekToEnd();
		CString strLine;
		for (int i = 0; i < noOfRow; i++)
		{
			for (int j = 0; j < noOfCol; j++)
			{
				CString strTemp = "";
				strTemp.Format("%16.9g, ", array[i][j]);
				strLine += strTemp;
			}
			strLine.TrimRight(',');
			outFile.WriteString(strLine);
			outFile.WriteString("\n");
			strLine.Empty();
		}
		outFile.Close();
	}
}

void print2dArray(double* array, CString filename, int noOfRow, int noOfCol, bool bAppend)
{
	CStdioFile outFile;

	CFileException expFile;
	UINT openFlags = CFile::modeCreate | CFile::modeWrite;
	if (bAppend)
		openFlags |= CFile::modeNoTruncate;

	if (!outFile.Open(filename, openFlags, &expFile))
	{
		AfxMessageBox("Failed to create file ...");
		return;
	}
	else
	{
		outFile.SeekToEnd();
		CString strLine;
		for (int i = 0; i < noOfRow; i++)
		{
			for (int j = 0; j < noOfCol; j++)
			{
				CString strTemp = "";
				strTemp.Format("%16.9g, ", array[i*noOfCol + j]);
				strLine += strTemp;
			}
			strLine.TrimRight(',');
			outFile.WriteString(strLine);
			outFile.WriteString("\n");
			strLine.Empty();
		}
		outFile.Close();
	}
}

