#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include "diag.h"
#include "geometry.h"
#include "init.h"

extern  char line[];		/*  parsing buf. (init)	*/

float	ct_Focal_mean;		/*  focal dist. (mean) (cm)	*/
float	ct_Focal_std;		/*  focal dist. (std) (cm)	*/
float	ct_PSpread_mean;	/*  pt. spread fn. (mean) (cm)	*/
float	ct_PSpread_std;		/*  pt. spread fn. (std) (cm)	*/
float	ct_Adjustment_std;	/*  adjustment dev. (std) (cm)	*/
float	ct_BlackSpot_rad;	/*  black spot radius (cm)	*/
float	ct_RMirror;		/*  rad. of single mirror (cm)	*/
int	ct_NMirrors=0;		/*  number of mirrors		*/
float	ct_CameraWidth;		/*  camera width (cm)		*/
int	ct_NPixels;		/*  number of pixels		*/
float	ct_PixelWidth;		/*  pixel width (cm)		*/

mirror *ct_data=NULL;		/*  ptr to mirror data		*/
FILE   *ct_BinaryData=NULL;	/*  binary data for mirrors     */
char	ct_BinaryName[128];	/*  binary data filename        */

int	nReflectivity=0;	/*  elements in refl. table	*/
float   *Reflectivity[2];	/*  reflectivity table		*/
float   *AxisDeviation[2];	/*  axis deviation table	*/
float   *ct_Focal;		/*  focal length table		*/

/*  Prototypes  */
static void ReadMirrorTable(FILE *geofile);
static void ReadReflectivity(char *datname);
static void ReadAxisDev(char *datname);
static void ReadFocals(void);

static void ReadMirrorTable(FILE *geofile)
{   int i;	/*  Mirror index	*/

    if ((ct_data=(mirror *)malloc(sizeof(mirror)*ct_NMirrors)) == NULL)
	FatalError(MIRR_ALLOC_FTL, ct_NMirrors);
    Log(MIRR_ALLOC_LOG, ct_NMirrors);
    Log(MIRR_TABLE_LOG);
    if (ct_BinaryData)
    {	Log(BINF_OPEN__LOG, ct_BinaryName);
	fread(ct_data, sizeof(mirror), ct_NMirrors, ct_BinaryData);
	fclose(ct_BinaryData); }
    else
    {	/*  read ASCII data  */
	Log(READ_ASCII_LOG);
	for (i=0; i<ct_NMirrors; i++)
	{   if (12 != fscanf(geofile, "%d %f %f %f %f %f %f %f %f %f %f %f",
		&ct_data[i].i,	    &ct_data[i].f,
		&ct_data[i].sx,	    &ct_data[i].sy,
		&ct_data[i].x,	    &ct_data[i].y,	&ct_data[i].z,
		&ct_data[i].theta,  &ct_data[i].phi,
		&ct_data[i].xn,	    &ct_data[i].yn,	&ct_data[i].zn))
		break;
	    Log("[%d]", ct_data[i].i);  }
	Log("%c", '\n');
	if (i < ct_NMirrors)
	    FatalError(MIRR_FEW___FTL, i);
	/*  Data Ok: save binary data for next time	*/
	if ((ct_BinaryData=fopen(ct_BinaryName, "w"))==NULL)
	    Log(BINF_ERROR_LOG, ct_BinaryName);
	else
	{   Log(BINF_WRITE_LOG, ct_BinaryName);
	    fwrite(ct_data, sizeof(mirror), ct_NMirrors, ct_BinaryData);
	    fclose(ct_BinaryData);	}
    }   /*  end of if: reading ASCII data  */
}   /*  end of ReadMirrorTable  */

static void ReadReflectivity(char *datname)
{   FILE *datfile = fopen(datname, "r");
    int current = 0;

    if (datfile == NULL)
	FatalError(RFLF_ERROR_FTL, datname);
    while (fgets(line, LINE_MAX_LENGTH, datfile))
    {	if (line[0] == '#') continue;
	if (nReflectivity == 0)
	{   nReflectivity = atoi(line);
	    if (nReflectivity)
	    {   if ((Reflectivity[0] =
		    (float *) malloc(sizeof(float) * nReflectivity)) == NULL
		 || (Reflectivity[1] =
		    (float *) malloc(sizeof(float) * nReflectivity)) == NULL)
		    FatalError(REFL_ALLOC_FTL, nReflectivity);  }}
	else if (2 == sscanf(line, "%f %f",
		&Reflectivity[0][current], &Reflectivity[1][current]));
	{   current++;
	    if (current >= nReflectivity) break; }}
    fclose(datfile);

    nReflectivity = current;
}   /*  end of ReadReflectivity  */

static void ReadAxisDev(char *datname)
{   FILE *datfile = fopen(datname, "r");
    int current = 0;

    if (datfile == NULL)
	FatalError(AXIS_ERROR_FTL, datname);
    if ((AxisDeviation[0]=
	(float *) malloc(sizeof(float) * ct_NMirrors)) == NULL
     || (AxisDeviation[1]=
	(float *) malloc(sizeof(float) * ct_NMirrors)) == NULL)
	FatalError(AXIS_ALLOC_FTL, ct_NMirrors);
    while (fgets(line, LINE_MAX_LENGTH, datfile))
    {	if (line[0] == '#') continue;
	if (2==sscanf(line, "%f %f",
	    &AxisDeviation[0][current], &AxisDeviation[1][current]));
	{   current++;
	    if (current >= ct_NMirrors) break; }}
    fclose(datfile);

    if (current != ct_NMirrors)
	FatalError(AXIS_FEW___FTL, current, ct_NMirrors);
}   /*  end of ReadAxisDev  */

static void ReadFocals(void)
{   int loop;

    if ((ct_Focal = (float *) malloc(sizeof(float) * ct_NMirrors)) == NULL)
	FatalError(FOCL_FEW___FTL, ct_NMirrors);

    for (loop=0; loop<ct_NMirrors; loop++)
	ct_Focal[loop] = ct_data[loop].f;
}   /*  end of ReadFocals  */

void GeometrySwitch(FILE *geofile)
{   char *value_ptr = NULL;	/*  ptr at parm value	*/
    int   switch_end = FALSE;	/*  bool to exit loop	*/
    extern char whites[];	/*  white chars (init)	*/
    extern int ParseLine(FILE *parfile,		    /*  FILE with parms	*/
			 const char *token_list[],  /*  array w/tokens	*/
			 int tokens,		    /*  nr of tokens	*/
			 char **value_ptr);	    /*  ptr->parm val.	*/

    /*	Initialise arrays  */
    Reflectivity[0] = AxisDeviation[0] = NULL;

    do  
    {	switch(ParseLine(geofile, ctparms, ARRAY_SZ(ctparms), &value_ptr))
	{   case type:
		 if (1 != atoi(value_ptr))
		     FatalError(TYPE_ERROR_FTL);
		 break;
	    case focal_distance:
		 Log(LOG__FLOAT_LOG, "focal distance (average)",
		     ct_Focal_mean = (float) atof(value_ptr));
		 break;
	    case focal_std:
		 Log(LOG__FLOAT_LOG, "focal distance (std. dev.)",
		     ct_Focal_std = (float) atof(value_ptr));
		 break;
	    case point_spread:
		 Log(LOG__FLOAT_LOG, "point spread fn. (average)",
		     ct_PSpread_mean = (float) atof(value_ptr));
		 break;
	    case point_std:
		 Log(LOG__FLOAT_LOG, "point spread fn. (std. dev.)",
		     ct_PSpread_std = (float) atof(value_ptr));
		 break;
	    case adjustment_dev:
		 Log(LOG__FLOAT_LOG, "adjustment dev. (std. dev.)",
		     ct_Adjustment_std = (float) atof(value_ptr));
		 break;
	    case black_spot:
		 Log(LOG__FLOAT_LOG, "radius of black spot (cm)",
		     ct_BlackSpot_rad = (float) atof(value_ptr));
		 break;
	    case r_mirror:
		 Log(LOG__FLOAT_LOG, "single mirror radius (cm)",
		     ct_RMirror = (float) atof(value_ptr));
		 break;
	    case n_mirrors:
		 Log(LOG__INT___LOG, "number of mirrors",
		     ct_NMirrors = atoi(value_ptr));
		 break;
	    case camera_width:
		 Log(LOG__FLOAT_LOG, "camera width (cm)",
		     ct_CameraWidth = (float) atof(value_ptr));
		 break;
	    case n_pixels:
		 Log(LOG__INT___LOG, "number of pixels",
		     ct_NPixels = atoi(value_ptr));
		 break;
	    case pixel_width:
		 Log(LOG__FLOAT_LOG, "pixel width (cm)",
		     ct_PixelWidth = (float) atof(value_ptr));
		 break;
	    case refl_file:
		 ReadReflectivity(value_ptr);
		 break;
	    case axisdev_file:
		 ReadAxisDev(value_ptr);
		 break;
	    case define_mirrors:
		 if (ct_NMirrors) ReadMirrorTable(geofile);
		 else FatalError(MIRR_NSPEC_FTL);
		 switch_end = TRUE;
		 break;
	    default: switch_end = TRUE;
		     break;  }}
    while (!switch_end);
    fclose(geofile);

    if (Reflectivity[0] == NULL) ReadReflectivity(REFLECTIVITY_FILE);
    if (AxisDeviation[0]== NULL) ReadAxisDev(AXISDEVIATION_FILE);
    ReadFocals();
}   /*  end of GeometrySwitch  */
