/*--------------------------------------------------------------------------*
 * File Name:	FortranDemoObj.cpp											*
 * Purpose:		Demonstrate accessing Fortran Libraries in Origin			*
 * Creation:	April	21, 2000											*
 *  	Copyright Microcal Software Inc. 2000								*
 *																			*
 * Modification Log:														*
 *--------------------------------------------------------------------------*/      

#include "FortranDemoObj.h"

//---------------------------------------------------------------------------
// THE_OMOCA_ENTRY_POINT(CDataSetDemo)
//
// This is the main object. A Moca project can have one and only one main
// object declared by the above command which communicates with Origin.
//---------------------------------------------------------------------------
MOCA_ENTRY_POINT(CFortran)


//---------------------------------------------------------------------------
// MOCA projects works with the aid of three types of tables
//		1) Property Tables
//		2) Methods Tables
//		3) Subobject Tables
//
// These tables are used for mapping LabTalk properties and methods to C++
// functions.
//
// 1) Properties(int, double or CString type as simple properties and functions with
//   arguments of above types as properties)
// 2) Methods(functions which accepts arguments from LabTalk)
// 3) Subobjects(Member Objects of the main Object and there member Objects....)
//   which can have there own properties, methods and subobjects.
// respectively. These Mappings are performed via. the Macros
// OMOCA_BEGIN_PROPERTY_MAP(CLASSNAME, BASECLASSNAME)
// ..........ENTRIES..................................
// OMOCA_END_PROPERTY_MAP(CLASSNAME, BASECLASSNAME)
// for property table, there are similar declaration for Methods and Subobjects
// Tables. The Entries can be of different types (See below) depending on the
// type of the arguments and access levels(Readonly or Writable)
// 
//  IMPORTANT!  IMPORTANT!  IMPORTANT!  IMPORTANT!  
// 
// Any class with subobject or methods table MUST have a property
// table, even if it has no entries!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//---------------------------------------------------------------------------


//---------------------------------------------------------------------------
// Property Map:
//
// The Property Map is for declaring the properties of your LabTalk object.
//
// A property is mapped to Get and Set function.  These functions allow
// you to do error checking or any necessary conversions.  A read-only
// property can be declared by using the _GET macro.
//
// MOCA_PROP_INT( <GetFunction>,<SetFunction>,<PropertyNameStr> )
// MOCA_PROP_REAL( <GetFunction>,<SetFunction>,<PropertyNameStr> )
// MOCA_PROP_STR( <GetFunction>,<SetFunction>,<PropertyNameStr> )
// MOCA_PROP_INT_GET( <GetFunction>,<PropertyNameStr> )
// MOCA_PROP_REAL_GET( <GetFunction>,<PropertyNameStr> )
// MOCA_PROP_STR_GET( <GetFunction>,<PropertyNameStr> )
//
// A Simple Property is mapped to a data member.  There are no Get/Set
// functions for a Simple Property.  MOCA will take care of the assignment.
// A simple read-only property can be declared by using the _GET macro.
//
// MOCA_SIMPLE_PROP_INT( <DataMember>,<PropertyNameStr> )
// MOCA_SIMPLE_PROP_REAL( <DataMember>,<PropertyNameStr> )
// MOCA_SIMPLE_PROP_STR( <DataMember>,<PropertyNameStr> )
// MOCA_SIMPLE_PROP_INT_GET( <DataMember>,<PropertyNameStr> )
// MOCA_SIMPLE_PROP_REAL_GET( <DataMember>,<PropertyNameStr> )
// MOCA_SIMPLE_PROP_STR_GET( <DataMember>,<PropertyNameStr> )
//---------------------------------------------------------------------------
MOCA_BEGIN_PROP_MAP(CFortran,	CMOCAObjBase)
MOCA_END_PROP_MAP(CFortran,		CMOCAObjBase)


//---------------------------------------------------------------------------
// Method Map:
//
// INPORTANT: To have a Method Map or a SubObject Map, you must
// have a property map.
//
// MOCA_METHOD( <MemberFunction>,<MethodNameStr> )
//
// <MemberFunction> must be declared as "BOOL foo(double &, CStringArray &);"
// The double is used for storing LabTalk's return value.
// The CStringArray contains the arguments passed from LabTalk.
//---------------------------------------------------------------------------
MOCA_BEGIN_METH_MAP(CFortran,	CMOCAObjBase)
	MOCA_METH_ENTRY(MethodCompute,		"COMPUTE")	
	MOCA_METH_ENTRY(MethodTranspose,	"TRANSPOSE")	
	MOCA_METH_ENTRY(MethodMultiply,		"MULTIPLY")	
	MOCA_METH_ENTRY(MethodPlot,			"PLOT")	
MOCA_END_METH_MAP(CFortran,		CMOCAObjBase)


//---------------------------------------------------------------------------
// SubObject Map:
//
// IMPORTANT: To have a Method Map or a SubObject Map, you must
// have a property map.
//
// MOCA_SUBOBJECT( <m_SubObject>,<SubObjectNameStr> )
//
//---------------------------------------------------------------------------
// This MOCA example has no subobjects.
// The following is an example of how a SubObject table is declared.
//OMOCA_BEGIN_SUBOBJECT_MAP(CLASSNAME, BASECLASSNAME)
//	OMOCAENTRY_SUBOBJECT(m_SubObject, "SUBOBJECT")
// 	OMOCAENTRY_SUBOBJECT(m_SubObject2, "SUBOBJECT2")
//OMOCA_END_SUBOBJECT_MAP(CLASSNAME, BASECLASSNAME)


//---------------------------------------------------------------------------
//	CFortran::CFortran()
//	CFortran::~CFortran()
//---------------------------------------------------------------------------

CFortran::CFortran()
{
}

CFortran::~CFortran()
{
}

//-------------------------------------------------------------------
//Make Calls to Fortran functions(Use Pointer Variables Only)
// The "C" attribute prevents C++ name mangling and is neede for every 
//Fortran routine declared
#ifdef __cplusplus
extern "C" 
#endif

float _stdcall  MOCAAMACH(int* n);

//unsigned char  _stdcall  MOCAACHAR(int* i);
#ifdef __cplusplus
extern "C" 
#endif
int _stdcall MNDAYS(int* IDAY, int* MONTH, int* IYEAR);
//-------------------------------------------------------------------


BOOL CFortran::MethodCompute(double &dValue, CStringArray &argarray)
{
	dValue = NANUM;

    int n;
    float rinfp;

    n = 7;
    rinfp = MOCAAMACH(&n);
	int i=64;
	int day = 21, month = 4, year = 2000;
	n = MNDAYS(&day, &month, &year);

	dValue = 0;
	return TRUE;
}

//-------------------------------------------------------------------
//Make Calls to Fortran functions(Use Pointer Variables Only)
#ifdef __cplusplus
extern "C" 
#endif
void _stdcall MOCATRNRR(int* NRA, int* NCA, float A[3][5], int* LDA, float B[5][3]);
//-------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////
//  TRANSPOSE(Source_Matrix_Name, Result_Matrix_Name)
//It calls the  Fortran function MOCATRNRR, which in tern calls an IMSL function 
//to find the transpose of a matrix. I have hard coded the dimensions of the matrices 
//and so the source matrix must be 5x3 and the destination 3x5, 
//there is a project test.opj in the Fortran folder that I used for testing.
BOOL CFortran::MethodTranspose(double &dValue, CStringArray &argarray)
{
	dValue = NANUM;
	if(argarray.GetSize() != 2)
		return FALSE;

	MoMatrix SourceMatrix(argarray[0]);
	//check validity
	if (! SourceMatrix.IsValid())
	{
		MessageBox(NULL, "Matrix not valid", "MDLLDemo", MB_OK);
		return FALSE;
	}

	int rows, cols;
	rows = (int)SourceMatrix.nRows();
	cols = (int)SourceMatrix.nCols();

	float z[3][5];
	float r[5][3];
	int i, j;
	for (i=0; i < rows; i++)
	{
		for (j=0; j < cols; j++)
			z[j][i] = SourceMatrix.val(i,j);
	}

	MOCATRNRR(&rows, &cols, z, &rows,r);

	double val; 
	MoMatrix ResultMatrix(argarray[1]);
	//check validity
	if (! ResultMatrix.IsValid())
	{
		MessageBox(NULL, "Matrix not valid", "MDLLDemo", MB_OK);
		return FALSE;
	}

	for ( i=0; i < cols; i++)
	{
		for (j=0; j < rows; j++)
		{
			val = r[j][i];
			ResultMatrix.SetVal(i , j, val);
		}
	}
	dValue = 0;
	return TRUE;
}

//-------------------------------------------------------------------
//Make Calls to Fortran functions(Use Pointer Variables Only)
#ifdef __cplusplus
extern "C" 
#endif
void _stdcall MOCAMULTIPLY(int* ROWS, float Z[20], float R[20]);
//-------------------------------------------------------------------

/////////////////////////////////////////////////////////////////////////
//MULTIPLY(Data_Set_Name, Result_Data_Set_Name)
//It multiplies the first data set by 5 and puts the result in the second data set.
//It calls a FORTRAN function MOCAMULTIPLY to perform the multiplication.
BOOL CFortran::MethodMultiply(double &dValue, CStringArray &argarray)
{
	dValue = NANUM;
	if(argarray.GetSize() != 2)
		return FALSE;

	MoSourceData SourceDataSet(argarray[0]);
	//check validity
	if (! SourceDataSet.IsValid())
	{
		MessageBox(NULL, "Dataset not valid", "MDLLDemo", MB_OK);
		return FALSE;
	}
	MoSourceData ResultDataSet(argarray[1]);
	//check validity
	if (! ResultDataSet.IsValid())
	{
		MessageBox(NULL, "Dataset not valid", "MDLLDemo", MB_OK);
		return FALSE;
	}

	int rows;
	rows = (int)SourceDataSet.iRange2() - (int)SourceDataSet.iRange1();

	float z[20];
	float r[20];

	for (int i=0; i < rows; i++)
	{
		z[i] = SourceDataSet[i];
	}

	MOCAMULTIPLY(&rows,  z, r);


	for (i=0; i < rows; i++)
	{
		ResultDataSet.SetValue(i, r[i]);
	}

	dValue = 0;
	return TRUE;
}


// avdef.h is the header file for the AView library
#include <avdef.h>
// avviewer.h provides the class declaration for the Array Viewer OLE interface.
#include <avviewer.h>
#include <conio.h>
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
//PLOT(matrix name)
//This method opens the Array Visualizer to plot the matrix
BOOL CFortran::MethodPlot(double &dValue, CStringArray &argarray)
{
	dValue = NANUM;
	if(argarray.GetSize() != 1)
		return FALSE;

	MoMatrix myMatrix(argarray[0]);
	//check validity
	if (! myMatrix.IsValid())
	{
		MessageBox(NULL, "Matrix not valid", "MDLLDemo", MB_OK);
		return FALSE;
	}

		//int dims[] = {5,5};
	int dims[2];
	dims[0] = myMatrix.nRows();
	dims[1] = myMatrix.nCols();
	float** z;

	// Use aglAlloc to allocate memory for the array.
	z = (float **)aglAlloc(2, dims, AGL_FLOAT);
	if (z == NULL)
	{
		printf("aglAlloc failed\n");
		return FALSE;
	}
	

	for (int i=0; i < myMatrix.nRows(); i++)
	{
		for (int j=0; j < myMatrix.nCols(); j++)
			z[i][j] = myMatrix[i,j];
	}

	
	CAViewer *pViewer = new CAViewer;

	// Did anything go wrong?
	int nError = pViewer->GetErrorNo();
	if (nError != 0) 
	{
		printf("Array Viewer reports error: %d\n", nError);
		return FALSE;
	}

		// SetArray tells the viewer to observe our array.
	nError = pViewer->SetArray(z);

	// Set the title bar on ArrayViewer
	pViewer->SetArrayName("test");

	// Set the palette to Rainbow_Inverted
	pViewer->SetPaletteId(CAViewer::RAINBOW_INVERTED);
	pViewer->SetShowPalette(TRUE);

	// Array Viewer comes up hidden, use ShowWindow(TRUE) to make it visible
	// on the screen.
	pViewer->ShowWindow(TRUE);
	aglFree(z);
	delete pViewer;
	dValue = 0;
	return TRUE;
}

