#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)	*/
extern  char axisdev_filename[256], reflectivity_filename[256];

float	ct_Focal_mean;		/*  focal dist. (mean) (cm)	*/
float	ct_PSpread_mean;	/*  pt. spread fn. (mean) (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)		*/
float   ct_max_radius;          /* Maximum value of curvilinear
				 * coordinates of the center of
				 * the mirrors.
				 */

mirror *ct_data=NULL;		/*  ptr to mirror data		*/

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

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

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

    ct_max_radius = 0.;

    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);

    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;

	ct_max_radius = 
	  (fabs(ct_data[i].sx) > ct_max_radius? fabs(ct_data[i].sx) : 
	   ct_max_radius);
	ct_max_radius = 
	  (fabs(ct_data[i].sy) > ct_max_radius? fabs(ct_data[i].sy) : 
	   ct_max_radius);
      }

    if (i < ct_NMirrors)
      FatalError(MIRR_FEW___FTL, i);

}   /*  end of ReadMirrorTable  */

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

    if (datfile == NULL)
	FatalError(RFLF_ERROR_FTL, datname);
    else
      printf("Reading file %s\n", 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);
    else
      printf("Reading file %s\n", axisdev_filename);

    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  */

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, cm)",
		     ct_Focal_mean = (float) atof(value_ptr));
		 break;
	    case focal_std:  /* not implemented. */
		 break;
	    case point_spread:
		 Log(LOG__FLOAT_LOG, "point spread fn. sigma (average, cm)",
		     ct_PSpread_mean = (float) atof(value_ptr));
		 break;
	    case point_std:  /* not implemented */
		 break;
	    case adjustment_dev:  /* not implemented */
		 break;
	    case black_spot:
		 Log(LOG__FLOAT_LOG, "radius of black spot (cm)",
		     ct_BlackSpot_rad = (float) atof(value_ptr));
		 break;
	    case n_mirrors:
		 Log(LOG__INT___LOG, "number of mirrors",
		     ct_NMirrors = atoi(value_ptr));
		 break;
	    case r_mirror:
		 Log(LOG__FLOAT_LOG, "single mirror radius (cm)",
		     ct_RMirror = (float) atof(value_ptr));
		 break;
	    case camera_width:
		 Log(LOG__FLOAT_LOG, "camera radius (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 n_centralpixels:
		 /* this parameter is for camera, not for reflector */
		 break;
	    case n_gappixels:
		 /* this parameter is for camera, not for reflector */
		 break;
	    case refl_file:
		 ReadReflectivity(value_ptr);
		 break;
	    case axisdev_file:
		 ReadAxisDev(value_ptr);
		 break;
	    case chessboarded_panels:
	         /* Nothing to be done. The flag will be written to the 
                    ascii tail of the reflector output. */ 
	         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);

    ct_max_radius += ct_RMirror;

    if (strlen(reflectivity_filename) == 0)
      strcpy(reflectivity_filename, REFLECTIVITY_FILE);
    if (Reflectivity[0] == NULL) ReadReflectivity(reflectivity_filename);

    if (strlen(axisdev_filename) == 0)
      strcpy(axisdev_filename, AXISDEVIATION_FILE);
    if (AxisDeviation[0]== NULL) ReadAxisDev(axisdev_filename);


}   /*  end of GeometrySwitch  */

