/* $Id: amber_ascii_export.c,v 1.9 2013-09-16 14:56:43 agabasch Exp $
 *
 * This file is part of the AMBER Pipeline
 * Copyright (C) 2002,2003 European Southern Observatory
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

/*
 * $Author: agabasch $
 * $Date: 2013-09-16 14:56:43 $
 * $Revision: 1.9 $
 * $Name: not supported by cvs2svn $
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

/* AMDLIB usage switch */
#define USE_AMDLIB YES

/*-----------------------------------------------------------------------------
                                Includes
 -----------------------------------------------------------------------------*/

#include <math.h>
#include <cpl.h>
#include <string.h>
#include "amdrs.h"

  /* AMBER structures */
  amdlibINS_CFG        insCfg; 
  amdlibOI_ARRAY       array;
  amdlibOI_TARGET      target;
  amdlibPHOTOMETRY     photometry;
  amdlibVIS            vis;
  amdlibVIS2           vis2;
  amdlibVIS3           vis3;
  amdlibWAVELENGTH     wave;
  amdlibPISTON         pst;
  amdlibSPECTRUM       spectrum={NULL};
  amdlibERROR_MSG      errMsg;

  double *tmpArray[amdlibNBASELINE];
  double threshold[amdlibNBASELINE];

  /* CPL data */
  cpl_frame         *  pFrame;
  cpl_propertylist  *  pHeader;

  cpl_parameterlist *  gparlist; 
  cpl_frameset      *  gframelist;

  FILE              *  pFITSFile;

  const char * expMethod1 = "Export SNR, Vis2";
  const char * expMethod2 = "Export Vis2, UV";
  const char * expMethod3 = "Export Clos.Ph.";
  const char * expMethod4 = "Yorick, 3T";
  //const char * selMethod5 = "Flux_percentage_x";
  //const char * selMethod6 = "Exclude_Frames_by_ASCII_File";
  //const char * selMethod7 = "Include_Frames_by_ASCII_File";
  //const char * selMethod8 = "IO-Test_no_filtering";


/*-----------------------------------------------------------------------------
                            Functions prototypes
 -----------------------------------------------------------------------------*/
static int amber_ascii_export_create(cpl_plugin *) ;
static int amber_ascii_export_exec(cpl_plugin *) ;
static int amber_ascii_export_destroy(cpl_plugin *) ;
static int amber_ascii_export(cpl_parameterlist *, cpl_frameset *) ;


/*-----------------------------------------------------------------------------
                            Static variables
 -----------------------------------------------------------------------------*/



static char amber_ascii_export_man[] =
"This recipe exports data stored in an AMBER OI product into ASCII files, two export methods are present\n"
"\n";

/*-----------------------------------------------------------------------------
                                Functions code
 -----------------------------------------------------------------------------*/

#define amdlib_OI_REVISION 1 /*Current revision number*/
#define amdlibNM_TO_M   1e-9 /* conversion nanometers to meters */

/** Usefull macro to error when reading/writing IO6FITS file */ 
#define amdlibOiReturnError(routine,msg)                        \
    fits_get_errstatus(status, (char*)fitsioMsg);               \
    amdlibError("%s(): %s - %s\n", routine, msg, fitsioMsg);    \
    sprintf(errMssg, "%s(): %s - %s", routine, msg, fitsioMsg);  \
    return (amdlibFAILURE)



/*----------------------------------------------------------------------------*/
/**
  @brief    Build the list of available plugins, for this module. 
  @param    list    the plugin list
  @return   0 if everything is ok

  This function is exported.
 */
/*----------------------------------------------------------------------------*/
int cpl_plugin_get_info(cpl_pluginlist * list)
{
    cpl_recipe  *   recipe = cpl_calloc(1, sizeof(*recipe)) ;
    cpl_plugin  *   plugin = &recipe->interface ;

    cpl_plugin_init(plugin,
                    CPL_PLUGIN_API,
                    AMBER_BINARY_VERSION,
                    CPL_PLUGIN_TYPE_RECIPE,
                    "amber_ascii_export",
                    "AMBER frame data to ASCII export",
                    amber_ascii_export_man,
                    "Klara Shabun",
                    "kshabun@eso.org",
                    "GP",
                    amber_ascii_export_create,
                    amber_ascii_export_exec,
                    amber_ascii_export_destroy) ;

    cpl_pluginlist_append(list, plugin) ;
    
    return 0;
}

/*----------------------------------------------------------------------------*/
/**
  @brief    Setup the recipe options    
  @param    plugin  the plugin
  @return   0 if everything is ok

  Create the recipe instance and make it available to the application using the 
  interface. 
 */
/*----------------------------------------------------------------------------*/
static int amber_ascii_export_create(cpl_plugin * plugin)
{
    cpl_recipe * recipe = (cpl_recipe *)plugin ;
    cpl_parameter * p ;

    /* Create the parameters list in the cpl_recipe object */
    recipe->parameters = cpl_parameterlist_new() ; 

    /* Fill the parameters list */
   

    /* Selection Method */
    p = cpl_parameter_new_enum( "amber.amber_ascii_export.export_method",
                                CPL_TYPE_STRING,
                                "Export methods",
                                "amber.amber_ascii_export",
                                expMethod1, 4, 
			        expMethod1, expMethod2, expMethod3, expMethod4 );

    cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "export-method") ;
    cpl_parameterlist_append(recipe->parameters, p) ;

    /* selection threshold float */
 /*   p = cpl_parameter_new_value("amber.amber_ascii_export.selection_x", 
            CPL_TYPE_DOUBLE, "X Value", "amber.amber_ascii_export", 2.0 ) ;
    cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "X") ;
    cpl_parameterlist_append(recipe->parameters, p) ;
*/
    /* Return */
    return 0;
}

/*----------------------------------------------------------------------------*/
/**
  @brief    Execute the plugin instance given by the interface
  @param    plugin  the plugin
  @return   0 if everything is ok
 */
/*----------------------------------------------------------------------------*/
static int amber_ascii_export_exec(cpl_plugin * plugin)
{
    cpl_recipe * recipe = (cpl_recipe *)plugin ;
    return amber_ascii_export(recipe->parameters, recipe->frames) ;
}

/*----------------------------------------------------------------------------*/
/**
  @brief    Destroy what has been created by the 'create' function
  @param    plugin  the plugin
  @return   0 if everything is ok
 */
/*----------------------------------------------------------------------------*/
static int amber_ascii_export_destroy(cpl_plugin * plugin)
{
    cpl_recipe  *   recipe = (cpl_recipe *)plugin ;
    cpl_parameterlist_delete(recipe->parameters) ; 
    return 0 ;
}

/*----------------------------------------------------------------------------*/
/**
  @brief    Get the command line options and execute the data reduction
  @param    parlist     the parameters list
  @param    framelist   the frames list
  @return   0 if everything is ok
 */
/*----------------------------------------------------------------------------*/
static int amber_ascii_export(
        cpl_parameterlist  *   parlist, 
        cpl_frameset       *   framelist)
{
 
  /* CPL structures */
  cpl_frame     * cur_frame;
  cpl_parameter * cur_param; 

  char   szMessage[1024];
  char   szFilnameOI[1024];
  char   szFileName[1024];
  char   szProductfile[1024];
  char   szASCII1[1024];
  char   szASCII2[1024];
  char   szASCII3[1024];
  char   szMethod[1024];
  char   szBuffer[1024];
  char   szLine[4096];
  char   szRA[15];
  char   szDEC[15];
  char   szRDB[1024];
  char   szFDATE[30]; 
  char * pszFilename;
  char * pszFileTag;
  FILE * fp1 = NULL;
  FILE * fp2 = NULL;
  FILE * fp3 = NULL;

/*  cpl_frame        *  pFrame;
  cpl_propertylist *  pHeader;*/

  gframelist = framelist;
  gparlist   = parlist;

  int  iStatus      = 0;
  int  iIsScience   = -1; /* neither SCIENCE or CALIB */   
  int  iFrameCount  = 0;
  
  cur_frame   = NULL;
  pszFilename = NULL;
  pszFileTag  = NULL;

  cpl_frameset_iterator * it = NULL;
  
  const char * fctid = "amber_ascii_export";
  strcpy( szProductfile, "amber_filtered.fits" );

  /* Read the parameters */
 // cur_param  = cpl_parameterlist_find( parlist, "amber.amber_ascii_export.selection_x" ); 
 // fThreshold = cpl_parameter_get_double( cur_param );  
  cur_param  = cpl_parameterlist_find( parlist, "amber.amber_ascii_export.export_method" ); 
  strcpy( szMethod, cpl_parameter_get_string( cur_param ) );  

  sprintf ( szMessage, "Using Method: %s", szMethod );
  cpl_msg_info( fctid, "%s", szMessage ); 
  

  cpl_msg_info( fctid, "Start of DataReduction");

 
  it = cpl_frameset_iterator_new(framelist);

  while((cur_frame = cpl_frameset_iterator_get(it)))
  {
 
    iFrameCount++;

    /* Get Filename and Classification Tag */
   pszFilename = (char *)cpl_frame_get_filename( cur_frame );
   pszFileTag  = (char *)cpl_frame_get_tag( cur_frame );
    
    /* Check Tag and Filename */
    if( pszFilename && pszFileTag )
    {
      sprintf( szMessage, "Frame #%d [Current execution status=%d]", iFrameCount, iStatus );
      cpl_msg_info( fctid, "%s", szMessage );   



  /* SCIENCE OR SCIENCE_CALIB OBJECT */
     if( !strcmp( pszFileTag, "SCIENCE_REDUCED" ) || !strcmp( pszFileTag, "SCIENCE_REDUCED_FILTERED" ) || !strcmp( pszFileTag, "SCIENCE_CALIBRATED" ) )
     {
           /* This is a SCIENCE frame */         
            iIsScience = 1; 
            strcpy( szFilnameOI, pszFilename );
     }  /* All SCIENCE frames */ 
     else if( !strcmp( pszFileTag, "CALIB_REDUCED" ) || !strcmp( pszFileTag, "CALIB_REDUCED_FILTERED" ) )
     {
       /* This is a CALIB frame */
            iIsScience = 0; 	   
            strcpy( szFilnameOI, pszFilename );
     }  /* All CALIB frames */ 

  




   /* Searching for SCIENCE_REDUCED */
//  cur_frame = cpl_frameset_find( framelist, "SCIENCE_REDUCED" );
//  if( cur_frame )
 // {
    /* This is a SCIENCE frame */
//   iIsScience = 1; 
//   strcpy( szFilnameOI, (char *)cpl_frame_get_filename( cur_frame ) );
//  }

  /* Searching for CALIB_REDUCED */
//  cur_frame = cpl_frameset_find( framelist, "CALIB_REDUCED" );

//  if( cur_frame )
//  {
    /* This is a CALIB frame */
//   iIsScience = 0; 	   
 //  strcpy( szFilnameOI, (char *)cpl_frame_get_filename( cur_frame ) );
//  }

  /* Searching for SCIENCE_REDUCED_FILTERED */
//  cur_frame = cpl_frameset_find( framelist, "SCIENCE_REDUCED_FILTERED" );
//  if( cur_frame )
//  {
    /* This is a SCIENCE frame */
//   iIsScience = 1; 
//   strcpy( szFilnameOI, (char *)cpl_frame_get_filename( cur_frame ) );
//  }

  /* Searching for CALIB_REDUCED_FILTERED */
//  cur_frame = cpl_frameset_find( framelist, "CALIB_REDUCED_FILTERED" );

//  if( cur_frame )
//  {
    /* This is a CALIB frame */
 //  iIsScience = 0; 	   
 //  strcpy( szFilnameOI, (char *)cpl_frame_get_filename( cur_frame ) );
 // }



  
  if( iIsScience != -1 )
  {
    amdlibClearInsCfg(&insCfg);
    /*if( amdlibLoadOiFile( szFilnameOI, &insCfg, &array, &target, &photometry,
                          &vis, &vis2, &vis3, &wave, &pst, errMsg ) == amdlibSUCCESS ) 
			  

    amdlib NEVER returns amdlibSUCCESS here?!?			  
    */

    iStatus = amdlibLoadOiFile( szFilnameOI, &insCfg, &array, &target, &photometry, &vis, &vis2, &vis3, &wave, &pst, &spectrum, errMsg );

    /*sprintf( szMessage, "%d", iStatus );
    cpl_msg_info( fctid, "%s", szMessage );*/
    


    /*   //ammyorick!!!!!!!!!!!!!!!!!->amdlibGetVis(&vis) 
  
  newVis = amdlibVIS();
      
  newVis.table = &array(amdlibVIS_TABLE_ENTRY, vis->nbBases, vis->nbFrames);
      
  for (base = 1; base <= vis->nbBases; base++)
    { 
      for (frame = 1; frame <= vis->nbFrames; frame++)
        {
          (*newVis.table)(base,frame).vis =
            &array(amdlibCOMPLEX, vis->nbWlen);
      
          (*newVis.table)(base,frame).sigma2Vis =
            &array(amdlibCOMPLEX, vis->nbWlen);
      
          (*newVis.table)(base,frame).visCovRI =
            &array(double, vis->nbWlen);
        }
    }
      
  */

    /* Fill Header function */;
/*      pHeader = cpl_propertylist_new();   */
     pHeader = cpl_propertylist_load(  szFilnameOI, 0 ); 

     sprintf( szMessage, "Extracting product header from file %s for target named %s [%s].",  szFilnameOI,  cpl_propertylist_get_string( pHeader, "ESO OBS NAME" ), cpl_error_get_message()  ); 
     cpl_msg_info( fctid, "%s", szMessage ); 

     sprintf( szMessage, "Target observed on %s [%s].",  cpl_propertylist_get_string( pHeader, "DATE-OBS" ), cpl_error_get_message()  ); 
     cpl_msg_info( fctid, "%s", szMessage );



    /* 1 seems to be a warning ?!? */
    if( iStatus == amdlibSUCCESS || iStatus == 1 ) 
    {
	    
      /* Reset to OK - no error */ 	    
      iStatus = 0;

     
      sprintf ( szMessage, "Status: %d for input file %s [%s]", iStatus, szFilnameOI, errMsg );
      cpl_msg_info( fctid, "%s", szMessage ); 
      
      /* Count number of frames */
      int iTotal =  vis.nbFrames * vis.nbBases;
      sprintf( szMessage, "Number of Frames = %d giving %d Visibilities",  iTotal / vis.nbBases, iTotal );
      cpl_msg_info( fctid, "%s", szMessage );

      /* Count frames for Photometry and Piston */
      
        sprintf( szMessage, "Photometry: %d / Piston: %d", photometry.nbFrames, pst.nbFrames );
        cpl_msg_info( fctid, "%s", szMessage );
      
      
      /* Count Frames with Fringe SNR greater than xxx */
      int iFrame        = 0;  
      int iFDate        = 0;
      int iFName        = 0;



      
      /*
      if (amdlibGetBand(wave.wlen[wave.nbWlen-1]) != band)
      {
        sprintf ( szMessage, "Sorry, frame selection is only possible for one band. This data contains more than one band" );
        cpl_msg_info( fctid, "%s", szMessage );       
	iStatus = 666;
      }
      */
        
  /*    strcpy( szASCII, "/tmp/amber_export_test.txt" );

      ft = fopen( szASCII, "wt" );
      if( ft )
      {
       sprintf( szLine, vis.table[0].vis)
       fputs( szLine, ft );
       fclose( ft );
      } 
*/    

     sprintf(szFDATE, cpl_propertylist_get_string( pHeader, "DATE-OBS" )); 
     
     strcpy( szFileName, szFilnameOI);
   
      while (szFDATE[iFDate] != '\0')
      {
         if (szFDATE[iFDate] == ':')
         szFDATE[iFDate] = '-';      
         iFDate++;
      } 

 sprintf ( szMessage, "New datetime format: %s", szFDATE);
   cpl_msg_info( fctid, "%s", szMessage ); 


      while (szFileName[iFName] != '\0')
      {
         if (szFileName[iFName] == ':')
         szFileName[iFName] = '-'; 
         iFName++;
      }

  sprintf ( szMessage, "New filename format: %s", szFileName);   
     cpl_msg_info( fctid, "%s", szMessage );   

 
    
      if( vis.nbBases == 1 )
      {
        sprintf( szBuffer, "%s_export_%s.txt",  szFDATE,  cpl_propertylist_get_string( pHeader, "ESO QC BAND" ) ); 
        strcpy( szASCII1, szBuffer );
      }
      else if ( !strcmp( szMethod, expMethod3 ) )
         { 
          sprintf( szBuffer, "%s_%s_cph.txt",  szFDATE,  cpl_propertylist_get_string( pHeader, "ESO QC BAND" )   ); 
          strcpy( szASCII1, szBuffer );
         }    
      else if ( !strcmp( szMethod, expMethod4 ) )
         { 
	   sprintf( szBuffer, "%s_y.txt",  szFDATE  ); 
          strcpy( szASCII1, szBuffer );

 sprintf ( szMessage, "Yorick filename format: %s", szBuffer);
   cpl_msg_info( fctid, "%s", szMessage ); 



         }        
      else
      {
        sprintf( szBuffer, "%s_%s1.txt",  szFDATE,  cpl_propertylist_get_string( pHeader, "ESO QC BAND" )   ); 
        strcpy( szASCII1, szBuffer );
        sprintf( szBuffer, "%s_%s2.txt",  szFDATE,  cpl_propertylist_get_string( pHeader, "ESO QC BAND" )   ); 
        strcpy( szASCII2, szBuffer );
        sprintf( szBuffer, "%s_%s3.txt",  szFDATE,  cpl_propertylist_get_string( pHeader, "ESO QC BAND" )   ); 
        strcpy( szASCII3, szBuffer );
      }
    //  strcpy( szASCII, "/tmp/amber_export.txt" );

      /* Variables */
      double fVisModul = 0;
      int    iTest = 0;
      int    iBase = 0;
      int    iWlen = 0;
      
      /* Open the ASCII file */
      if( vis.nbBases == 1 )
       fp1 = fopen( szASCII1, "wt" );
      else if ( !strcmp( szMethod, expMethod3 ) || !strcmp( szMethod, expMethod4 ) ) 
                 {
                   fp1 = fopen( szASCII1, "wt" );   

                   sprintf ( szMessage, "Yorick file %s  opened", szASCII1);
                   cpl_msg_info( fctid, "%s", szMessage ); 

                                 
                 }
      else
      {
       fp1 = fopen( szASCII1, "wt" );
       fp2 = fopen( szASCII2, "wt" );
       fp3 = fopen( szASCII3, "wt" );
      } 

#ifdef ONE_VIS_PER_LINE      
      if( fp )
      {
         /*----------------------------------------------------------------------------------------*/
	 /* Loop through frames and export several values                                          */
	 for (iFrame = 0; iFrame < vis.nbFrames && !iStatus; iFrame++)
         {
           /*for (base = 0; base < vis.nbBases; base++)*/
           {
              /* vis.table[iFrame].frgContrastSnr; */
             // fVisibility =  vis.table[iFrame].vis->re + vis.table[iFrame].vis->im;
	     
              fVisModul = sqrt( pow(vis.table[iFrame].vis->re,2) + pow(vis.table[iFrame].vis->im,2) );
		   
              /* Create one line of output */
	      sprintf( szLine, "%d\t %0.3f\t %0.5f\t %0.5f\t %0.5f\t %0.5f\t %d %d %f \n", 
			        iFrame, 
			        vis.table[iFrame].frgContrastSnr,
				vis.table[iFrame].vis->re,
				vis.table[iFrame].vis->im,
				fVisibility,
				fVisModul,
				vis.table[iFrame].stationIndex[0],
				vis.table[iFrame].stationIndex[1],
				vis.table[iFrame].time);
	      
	      fputs( szLine, fp );
           }
         } /* all frames */
	

	    fclose( fp );	  
      } /* if file */
#endif      

      if( fp1 )
      {
         /*----------------------------------------------------------------------------------------*/

         /* Create a file header*/

         strcpy( szRDB, cpl_propertylist_get_comment( pHeader, "RA" ));
         strncpy( szRA, szRDB, 11);
         szRA[11]='\0';
         strcpy( szRDB, cpl_propertylist_get_comment( pHeader, "DEC" )); 
         strncpy( szDEC, szRDB, 11);
         szDEC[11]='\0';


         if( vis.nbBases == 1 )
         {
         sprintf( szLine, "OBS\t OBJECT\t RA\t DEC\t UT\t LST\t PBL12\n");
         fputs( szLine, fp1 );
         }
         else
         {
         sprintf( szLine, "OBS\t OBJECT\t RA\t DEC\t UT\t LST\t PBL%d%d\t PBL%d%d\t PBL%d%d \n", 
                  vis.table[0].stationIndex[0],
		  vis.table[0].stationIndex[1],
                  vis.table[1].stationIndex[0],
		  vis.table[1].stationIndex[1],
                  vis.table[2].stationIndex[0],
		  vis.table[2].stationIndex[1]);

         if ( !strcmp( szMethod, expMethod3 ) || !strcmp( szMethod, expMethod4 ) )
         fputs( szLine, fp1 );
         else
         { 
         fputs( szLine, fp1 );
         fputs( szLine, fp2 );
         fputs( szLine, fp3 );
         }          
         }

         if( vis.nbBases == 1 )
         {
         sprintf( szLine, "%s\t %s\t %s\t %s\t %s\t %s\t %0.3f\n", cpl_propertylist_get_string( pHeader, "ESO OBS NAME" ), cpl_propertylist_get_string( pHeader, "ESO OBS TARG NAME" ), szRA, szDEC, cpl_propertylist_get_string( pHeader, "UT"), cpl_propertylist_get_string( pHeader, "ST"),  cpl_propertylist_get_double( pHeader, "ESO ISS PBL12 START") );
         fputs( szLine, fp1 );
         }
         else
         {
         sprintf( szLine, "%s\t %s\t %s\t %s\t %s\t %s\t %0.3f\t %0.3f\t %0.3f\n", cpl_propertylist_get_string( pHeader, "ESO OBS NAME" ), cpl_propertylist_get_string( pHeader, "ESO OBS TARG NAME" ), szRA, szDEC, cpl_propertylist_get_string( pHeader, "UT"), cpl_propertylist_get_string( pHeader, "ST"),  sqrt(pow(vis.table[0].uCoord,2)+pow(vis.table[0].vCoord,2)), sqrt(pow(vis.table[1].uCoord,2)+pow(vis.table[1].vCoord,2)), sqrt(pow(vis.table[2].uCoord,2)+pow(vis.table[2].vCoord,2)) );

         if ( !strcmp( szMethod, expMethod3 ) || !strcmp( szMethod, expMethod4 ) )
         fputs( szLine, fp1 );
         else
         { 
         fputs( szLine, fp1 );
         fputs( szLine, fp2 );
         fputs( szLine, fp3 );
         }   
       
         }
         
        /* Selection methods */
            if( !strcmp( szMethod, expMethod1 ) ) /* Method 1: Vis, Vis2 output*/
            {
             sprintf( szLine, "\t iFrame\t \t SNR\t \t iWlen\t \t Wlen\t \t Vis2\n");
            }
            else  /* Method 2: Vis, UV output */ 
            if( !strcmp( szMethod, expMethod2 ) )
            {
      	     sprintf( szLine, "iFrame\t iVF\t Base\t LST\t SNR\t uCoord\t vCoord\t PBL\t iWlen\t Wlen\t VisMod\t VisMod^2\t Vis2\n");
            }
            else  /* Method 3: Closure phases output */ 
            if( !strcmp( szMethod, expMethod3 ) )
            {
      	     sprintf( szLine, "iFrame\t  LST\t SNR\t iWlen\t Wlen\t CPAmp\t CPPhi\t CPAv\n");
            }
            else  /* Method 4: Yorick products output */ 
            if( !strcmp( szMethod, expMethod4 ) )
            {
      	     sprintf( szLine, "iWlen\t Wlen\t sqVis1\t sqVisErr1\t sqVis2\t sqVisErr2\t sqVis3\t sqVisErr3\t CP\t CPErr\n");
            }

            if( vis.nbBases == 1 )
            fputs( szLine, fp1 );
            else if ( !strcmp( szMethod, expMethod3 ) || !strcmp( szMethod, expMethod4 ) )
            {
             fputs( szLine, fp1 );
            } 
            else
            {
            fputs( szLine, fp1 );
            fputs( szLine, fp2 );
            fputs( szLine, fp3 ); 
            }





    if( !strcmp( szMethod, expMethod4 ) )
      { 

              for (iWlen = 0; iWlen < vis.nbWlen; iWlen++)
                { 
                            
                      /* Create one line of output */
	               sprintf( szLine, "%d\t %0.5f\t %0.5f\t %0.5f\t %0.5f\t %0.5f\t %0.5f\t %0.5f\t %0.5f\t %0.5f\n", 
			        iWlen,
                                wave.wlen[iWlen]/1000,
				vis2.table[0].vis2[iWlen],
				vis2.table[0].vis2Error[iWlen],
				vis2.table[1].vis2[iWlen],
				vis2.table[1].vis2Error[iWlen],
				vis2.table[2].vis2[iWlen],
				vis2.table[2].vis2Error[iWlen],
                                vis3.table[0].vis3Phi[iWlen],  //Closure Phase phase
                                vis3.table[0].vis3PhiError[iWlen] );     
                 
                        fputs( szLine, fp1 );
                
               } /* iWlen */
           
      }
    else
      {
	 /* Loop through frames and export 3 Bases per Line - old;  now only in columns         */
	    for (iFrame = 0; iFrame < vis.nbFrames && !iStatus; /*iFrame+=3*/ iFrame++)
            {
              for (iBase = 0; iBase < vis.nbBases; iBase++)
              {
                   if( vis.nbBases == 1 )
                     iTest = iFrame;
                   else             
                     iTest = iFrame*3+iBase;
             

                for (iWlen = 0; iWlen < vis.nbWlen; iWlen++)
                { 

                   fVisModul = sqrt( pow(vis.table[iTest].vis[iWlen].re,2) + pow(vis.table[iTest].vis[iWlen].im,2) );
                  //fVisModul = sqrt( pow(vis.table[iTest].vis->re,2) + pow(vis.table[iTest].vis->im,2) );
		   
             
                   /* Selection methods */
                  if( !strcmp( szMethod, expMethod1 ) ) /* Method 1: Vis, Vis2 output*/
                  {
                     /* Create one line of output */
	               sprintf( szLine, "\t %d\t \t %0.3f\t \t %d\t \t %0.5f\t \t %0.5f\n", 
			        iFrame, 
                                vis.table[iTest].frgContrastSnr,
                                iWlen,
                                wave.wlen[iWlen]/1000,
				vis2.table[iTest].vis2[iWlen] );     
                  }
                  else  /* Method 2: Vis, UV output */ 
                  if( !strcmp( szMethod, expMethod2 ) )
                  {
      	               /* Create one line of output */
	               sprintf( szLine, "%d\t %d\t %d %d\t %0.3f\t %0.5f\t %0.5f\t %0.5f\t %0.5f\t %d\t %0.5f\t %0.5f\t %0.5f\t %0.5f\n", 
			        iFrame, 
                                iTest,
                                vis.table[iTest].stationIndex[0],
				vis.table[iTest].stationIndex[1],
                                vis.table[iTest].time,
			        vis.table[iTest].frgContrastSnr,
                                vis.table[iTest].uCoord,
                                vis.table[iTest].vCoord,
                                sqrt(pow(vis.table[iTest].uCoord,2)+pow(vis.table[iTest].vCoord,2)),
                                iWlen,
                                wave.wlen[iWlen]/1000,
                                fVisModul,
                                pow(fVisModul,2),
                                vis2.table[iTest].vis2[iWlen] );
                 }
                 else  /* Method 3: Closure phases output */ 
                 if( !strcmp( szMethod, expMethod3 ) )
                 {

                      if( iBase > 0 )
	              break; 

      	               /* Create one line of output */
	               sprintf( szLine, "%d\t %0.3f\t %0.5f\t %d\t %0.5f\t %0.5f\t %0.5f\t %0.5f\n", 
			        iFrame, 
                                //vis.table[iFrame].stationIndex[0],
				//vis.table[iFrame].stationIndex[1],
                                vis.table[iFrame].time,
			        vis.table[iFrame].frgContrastSnr,
                                iWlen,
                                wave.wlen[iWlen]/1000,
                                vis3.table[iFrame].vis3Amplitude[iWlen],  //ClPh amplitude
                                vis3.table[iFrame].vis3Phi[iWlen],  //ClPh phase
                                vis3.averageClosure);
                 }




                 if( vis.nbBases == 1 )
	         fputs( szLine, fp1 );
                 else if ( !strcmp( szMethod, expMethod3 ) ) 
                 {
                    fputs( szLine, fp1 );
                                    
                 }
                 else
                 {
                   switch ( iBase ) 
                   {
                    case 0 :   fputs( szLine, fp1 );
                    break; 
                    case 1 :   fputs( szLine, fp2 );
                    break;
                    case 2 :   fputs( szLine, fp3 );
                    break;
                   }
                }


              } /* iWlen */
            } /* iBase */
         } /* all frames */

       } /* else if expMethod4 */
	
         if( vis.nbBases == 1 )
	 fclose( fp1 );
         else if ( !strcmp( szMethod, expMethod3 ) || !strcmp( szMethod, expMethod4 ) )
         {
          fclose( fp1 );
         }
         else
         {
          fclose( fp1 );
          fclose( fp2 );
          fclose( fp3 );
         }	  
      } /* if file */

      cpl_propertylist_delete( pHeader ); 
          
    }
    else
    {
      /* not an AMBER file */
      iStatus = 2; 
      sprintf ( szMessage, "ERROR: Cannot read [%s]. OI table structure is not from AMBER or the file has been corrupted. [%s]", szFilnameOI, errMsg );
      cpl_msg_info( fctid, "%s", szMessage ); 	
    }
   }
   else /* found fitting frame ? */
   {
    /* no fitting frame */
    iStatus = 1; 
    sprintf ( szMessage, "ERROR: Current file doesn't contain SCIENCE_REDUCED or CALIB_REDUCED." );
    cpl_msg_info( fctid, "%s", szMessage ); 	
   }
  


  } /* Filename and Tag present */  	
  else
  {
   sprintf( szMessage, "Missing FileName or Tag for Frame #%d", iFrameCount ); 
   cpl_msg_info( fctid, "%s", szMessage );   
  } /* Filename and Tag present */    

    /* release memory */
    amdlibReleaseOiArray(&array);
    amdlibReleaseOiTarget(&target);
    amdlibReleasePhotometry(&photometry);
    amdlibReleaseVis(&vis);
    amdlibReleaseVis2(&vis2);
    amdlibReleaseVis3(&vis3);
    amdlibReleaseWavelength(&wave);
    amdlibReleaseSpectrum(&spectrum);
    amdlibReleasePiston(&pst);

    
 cpl_frameset_iterator_advance(it, 1);

} /* while more frames */

  cpl_frameset_iterator_delete(it);


 // if( pFrame && !iStatus )
 // {
    /*	  
    sprintf( szMessage, "cpl_frame_insert [%s]", cpl_frame_get_filename(pFrame ) ); 
    cpl_msg_info( fctid, "%s", szMessage );     
    */
 //   cpl_frameset_insert( framelist, pFrame );  		  
 // }
  
  /*
  sprintf ( szMessage, "Status: %d for %s", iStatus, szProductfile );
  cpl_msg_info( fctid, "%s", szMessage ); 
  */
 
  cpl_msg_info( fctid, "End of DataReduction");
 
  cpl_error_reset();
  
  return iStatus;
}
