/*char RcsId[] = "$Header: /scisoft/users/mirone/SOURCESCVS/specfile/src/sfmca.c,v 1.2 2003/02/12 09:00:35 mirone Exp $"; */
/************************************************************************
 *
 *   File:          sfmca.c
 *
 *   Project:       SpecFile library
 *
 *   Description:   Access to MCA spectra
 * 
 *   Author:        V.Rey
 *
 *   Date:          $Date: 2003/02/12 09:00:35 $
 *
 ************************************************************************/
/*
 *   Log: $Log: sfmca.c,v $
 *   Log: Revision 1.2  2003/02/12 09:00:35  mirone
 *   Log: just log comments
 *   Log:
 *   Log: Revision 3.0  2000/12/20 14:17:19  rey
 *   Log: Python version available
 *   Log:
 * Revision 2.1  2000/07/31  19:05:12  19:05:12  rey (Vicente Rey-Bakaikoa)
 * SfUpdate and bug corrected in ReadIndex
 * 
 * Revision 2.0  2000/04/13  13:28:54  13:28:54  rey (Vicente Rey-Bakaikoa)
 * New version of the library. Complete rewrite
 * Adds support for MCA
 */
#include <SpecFile.h>
#include <SpecFileP.h>

#include <ctype.h>
#include <stdlib.h>
/*
 * Define macro
 */
#define isnumber(this) ( isdigit(this) || this == '-' || this == '+'  || this =='e' || this == 'E' || this == '.' )

/*
 * Mca continuation character
 */
#define MCA_CONT '\\'
#define D_INFO   3

/*
 * Declarations
 */
DllExport long SfNoMca    ( SpecFile *sf, long index, int *error );
DllExport int  SfGetMca   ( SpecFile *sf, long index, long mcano, 
                                          double **retdata, int *error );
DllExport long SfMcaCalib ( SpecFile *sf, long index, double **calib, 
                                          int *error );


/*********************************************************************
 *   Function:        long SfNoMca( sf, index, error )
 *
 *   Description:    Gets number of mca spectra in a scan
 *
 *   Parameters:
 *        Input :    (1) File pointer   
 *            (2) Index
 *        Output:
 *            (3) error number
 *   Returns:
 *            Number of data lines , 
 *            ( -1 ) => errors.
 *   Possible errors:
 *            SF_ERR_SCAN_NOT_FOUND
 *
 *********************************************************************/
DllExport long
SfNoMca( SpecFile *sf, long index, int *error )
{

     if (sfSetCurrent(sf,index,error) == -1 )
             return(-1);

     return( ((SpecScan *)sf->current->contents)->mcaspectra );

}  


/*********************************************************************
 *   Function:        int SfGetMca(sf, index, number, data, error)
 *
 *   Description:    Gets data.
 *   Parameters:
 *        Input :    (1) File pointer   
 *            (2) Index
 *        Output:
 *            (3) Data array
 *            (4) Data info : [0] => no_lines
 *                    [1] => no_columns
 *                    [2] = ( 0 ) => regular    
 *                          ( 1 ) => not regular ! 
 *            (5) error number
 *   Returns:
 *            (  0 ) => OK
 *                ( -1 ) => errors occured
 *   Possible errors:
 *            SF_ERR_MEMORY_ALLOC   
 *            SF_ERR_FILE_READ
 *            SF_ERR_SCAN_NOT_FOUND
 *            SF_ERR_LINE_NOT_FOUND
 *
 *   Remark:  The memory allocated should be freed by the application
 *
 *********************************************************************/
DllExport int 
SfGetMca( SpecFile *sf, long index, long number, double **retdata, int *error )
{
     double  *data  = NULL;
     long     headersize;

     char *ptr,
          *from,
          *to;

     char    strval[100];
     double  val;

     int     i,spect_no=0;
     long    vals,nb_mca;

     long    blocks=1, 
             initsize=1024;

     char  **retline;
     char   *strptr;
     long    nb_lines,
             nb_pnts;

     nb_mca     = SfNoMca(sf,index,error);

     if (nb_mca == 0 || nb_mca == -1) {
          *retdata = (double *) NULL;
           return(-1);
     }
    /* 
     * try to guess number of points.
     * otherwise use default initsize
     */
     nb_lines   = SfHeader(sf,index,"@CHANN",&retline,error);

     if (nb_lines > 0) {
        strptr = retline[0] + 8; 
        sscanf(strptr,"%ld%*s",&nb_pnts);
        initsize = nb_pnts;
     } 

     headersize = ((SpecScan *)sf->current->contents)->data_offset
                - ((SpecScan *)sf->current->contents)->offset;

    /*
     *  check that mca number is available
     */
    if (nb_mca == 0 || number > nb_mca || number < 1) {
        *error = SF_ERR_MCA_NOT_FOUND;
        *retdata = (double *)NULL;
         return(-1);
    }
     
    /* 
     * Get MCA info from header
     */

     from = sf->scanbuffer + headersize;
     to   = sf->scanbuffer + ((SpecScan *)sf->current->contents)->size;

     /*
      * go and find the beginning of spectrum 
      */
     ptr = from;
  
     if ( *ptr == '@' ) {
         spect_no++;
         ptr++; 
     } 

     while ( spect_no != number  && ptr < to ) {
            if (*ptr == '@') spect_no++;
            ptr++;
     } 
     ptr++;

     if ( spect_no != number ) {
        *error = SF_ERR_MCA_NOT_FOUND;
        *retdata = (double *)NULL;
         return(-1);
     }

    /*
     * Calculate size and book memory
     */ 
     initsize = 2048;

     i    = 0;
     vals = 0;

     /*
      * Alloc memory
      */
     if ((data = (double *)malloc (sizeof(double) * initsize)) == (double *)NULL) {
         *error = SF_ERR_MEMORY_ALLOC;
          return(-1);
     }

    /*
     * continue
     */
     for ( ;(*(ptr+1) != '\n' || (*ptr == MCA_CONT)) && ptr < to - 1 ; ptr++)
     { 
         if (*ptr == ' ' || *ptr == '\t' || *ptr == '\\' || *ptr == '\n') {
             if ( i ) {
                if ( vals%initsize  == 0 ) {
                    blocks++;
                    if ((data = (double *)realloc (data, sizeof(double) * blocks * initsize)) 
                                       == (double *)NULL) {
                          *error = SF_ERR_MEMORY_ALLOC;
                          return(-1);
                    }

                }
                strval[i] = '\0';
                i = 0;
                val = atof(strval);
                data[vals] = val;
                vals++;
             }
         } else if (isnumber(*ptr)) {
             strval[i] = *ptr;
             i++;
         }
     }

     if (isnumber(*ptr)) {
       strval[i]    = *ptr;
       strval[i+1]  = '\0';
       val = atof(strval);
       data[vals] = val;
       vals++;
     }

    *retdata = data;

     return( vals );
}


DllExport long 
SfMcaCalib ( SpecFile *sf, long index, double **calib, int *error )
{

     long   nb_lines;
     char **retline;
     char  *strptr;

     double val1,val2,val3;

     double *retdata;

     nb_lines   = SfHeader(sf,index,"@CALIB",&retline,error);

     if (nb_lines > 0) {
          strptr = retline[0] + 8; 
          sscanf(strptr,"%lf %lf %lf",&val1,&val2,&val3);
     }  else {
         *calib = (double *)NULL;
          return(-1);
     }

     retdata = (double *) malloc(sizeof(double) * 3 );
     retdata[0] = val1; retdata[1] = val2; retdata[2] = val3;

     *calib = retdata;
     return(0);
}
