#include <windows.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>

/*
Written by Kenneth E. Moore
June 5, 2000
*/

int __declspec(dllexport) APIENTRY UserDiffraction(double *data);
int __declspec(dllexport) APIENTRY UserParamNames(char *data);

BOOL WINAPI DllMain (HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved)
	{
   return TRUE;
   }

/* the data is stored as follows:
data[0]  = the total number of values in the passed data array
data[1]  = x position
data[2]  = y position
data[3]  = z position
data[4]  = x cosine
data[5]  = y cosine
data[6]  = z cosine
data[7]  = x cosine surface normal
data[8]  = y cosine surface normal
data[9]  = z cosine surface normal
data[10] = wavelength in microns
data[11] = 0 if refractive surface, 1 for reflective. May be set by DLL if data[31] = 1 or 2
data[12] = approach side index
data[13] = exit side index
data[14] = order to be traced now
data[15] = starting order
data[16] = stopping order
data[17] = millimeters per unit length (1.0 for mm, 25.4 for inches, 10.0 for cm and 1000.0 for meters)
data[18] = a random value to use as a seed

data[20] = incident Ex real
data[21] = incident Ex imaginary
data[22] = incident Ey real
data[23] = incident Ey imaginary
data[24] = incident Ez real
data[25] = incident Ez imaginary

data[30] = relative energy (to be computed by the dll and returned)
data[31] = flag = 1 if DLL returns phase and phase derivatives; = 2 if complete output ray data

if the DLL sets data[31] = 1; then the DLL must return the phase and derivative.
if the DLL sets data[31] = 2; then the DLL must return complete ray data.

data 32-34 only need to be computed if the DLL sets data[31] = 1 or 2
data[32] = output phase added to ray
data[33] = derivative of the phase with respect to x
data[34] = derivative of the phase with respect to y

data 35-45 only need to be computed if the DLL sets data[31] = 2
data[35] = output x cosine
data[36] = output y cosine
data[37] = output z cosine

data[40] = output Ex real
data[41] = output Ex imaginary
data[42] = output Ey real
data[43] = output Ey imaginary
data[44] = output Ez real
data[45] = output Ez imaginary

data[51] = input parameter 1 from user
data[52] = input parameter 2 from user
etc... up to data[maxdata] where maxdata = int(data[0])

The DLL must set data 30 and 31 given the other data, and possibly data 32-45.

Return 0 if it works; else return -1.

*/

/* this DLL models a simple straight-line grating that puts equal energy into all diffracted orders */
/* the lines/micron is parameter 1 */

int __declspec(dllexport) APIENTRY UserDiffraction(double *data)
	{
   double N, T, Y, M, W, dPdX, dPdY, P;

   /* the energy is just 1over the total number of orders defined */
	N = fabs(data[16] - data[15]) + 1.0;
	data[30] = 1.0 / N;

	/* we will also return the phase and derivatives */
	data[31] = 1.0;
	
	/* lines per micron */
	T = data[51];

	/* local y coordinate in lens units */
	Y = data[2];

	/* current order */
	M = data[14];

	/* wavelength in microns */
	W = data[10];

	/* phase and derivatives*/
	dPdX = 0.0;
	dPdY = M*T*W; /* note this is dimensionless */
	P = dPdY*Y; /* note this is in lens units */

	data[32] = P;
	data[33] = dPdX;
	data[34] = dPdY;

	return 0;
   }

int __declspec(dllexport) APIENTRY UserParamNames(char *data)
	{
	/* this function returns the name of the parameter requested */
	int i;
	i = (int) data[0];
	strcpy(data,"");
	if (i == 1) strcpy(data,"lines/micron");
	return 0;
	}
