//***********************************************************************
//*           See Accompanying licence file QSAS_licence                *
//***********************************************************************

// Header for QIE File Object using QDOS 2 
// Allows read of file with single scan
// CAA compliant

// ensure cdf.h is included before declaractions dependent on CDF types 

#if !defined(___cdf_h___)
#include <cdf.h>
#endif
 
#ifndef _QIE_CAA_H_  
#define _QIE_CAA_H_


#include "Qdos.h"
#include "Xrefs.h"
#include <string> 

// DEFINES

#define _CAA 1
#define _CDF 2
#define _QFT 3
#define _QFD 4
#define _CEF 5

#define TO_UPPER_LEN 500

#define N_FT_DATE_STRINGS  6    /*SJS re FT*/
#define N_FT_TIME_STRINGS  9	/*SJS re FT*/
#define MAX_FT_LENGTH    256	/*SJS re FT*/
#define EPOCH_WIDTH  30


// Structures

typedef struct QieSVariable
{
  std::string name;     // title string for var name 
  std::string datatype; // data type for variable
  int  n_posn;          // start position in vector of tokens in record
  int  col_start;       // posn for var in record, start at 0 
  int  col_width;       // column width of var in record 
  bool ignore;		    // flag for variable for skipping cols in qft/qfd files
  bool recVary;		    // flag for variable true if record varying
  vector <int> objDim;	// list of data object dimensions
  int nEntries;		// Total number of entries (product of array dims)
//  QiFTpacket ftpacket;  // info for FreeTime->epoch conv SJS
  QdObject_var Vobj;     // The Qdos object itself for transferring to/from WL
  QdSMatrixSeq_var stms; // Type specific var ptr - string matrix sequence
  QdStringSeq_var   sts; // Type specific var ptr - string sequence
  QdTimeSeq_var      ts; // Type specific var ptr - time sequence
  QdTimeInterval_var ti; // Type specific var ptr - time interval
  QdRMatrixSeq_var   ms; // Type specific var ptr - matrix sequence
  QdRScalarSeq_var   ss; // Type specific var ptr - scalar sequence
  vector <QdObject_var> attrList;
  vector <std::string> attrNameList;
  bool getThis;         // flag for reading
  int nRecs;            // number of records (not always same for sparse cdf files)
  int cachedFrom;       // record start for variable after data read from cdf
  int cachedTo;         // record end for variable after data read from cdf
} QieVariable;


//-------------------------------------------
/// \class QieFile 
/// \brief This is the QieFile class
///
/// \remarks { This class implements file pointers for flat files }

class QieFile 
{
   
public:
   QieFile();
   ~QieFile();
   void  openFile(const char * fullName, const char *mode, bool overwrite=false);
   void  openIncludedFile(const char * fullName, const char *mode);
   void closeFile();
   void rewindFile();
   string readRecord();
   char readLine(string &line_ptr);
   char assembleLine(string &line_ptr, int &posn);
   void setEOL(char eol);
   void setCMark(char cmark);
   void setFileType(int ftype);
   void setDataUntil(std::string duntil);
   void setStartAfter(std::string safter);
   void setAttrDelim(char delim);
   void setDataDelim(char c);
   void setRecNumbering(bool recNumOn);
   bool skipNextRecord();
   int  skipRestOfLine();
   void addChar(int & posn, int &available, string &line_ptr, string &emptyBlock, char c);
         
   FILE * fp;
   char * name;
   bool is_gz;
   char  end_of_line;
   char  commentMark;
   char attr_delim;
   char data_delim;
   QieFile *includedFile;
   int fileType;
   std::string data_until;
   std::string start_after;
   bool recNumberingOn;

protected:

public: 

private:

	   
};

//-------------------------------------------
/// \class QieData
/// \brief This is the QieData class
///
/// \remarks { This class implements a CAA/CDF file object using QDOS classes
/// It provides native QSAS2 internals replicating the QIE QiSCDFContents object }

class QieData
{
   
public:
   QieData();
   ~QieData();
   bool readFlatFile(const char * fullName, const char * headerName = NULL);
   int  countDataRecords();
   bool queryFile(const char * fullName, const char * headerName = NULL);
   bool readHeader();
   bool readGlobal(const char *globalAttrName);
   bool readVariable(const char *variableName);
   bool readVarData(int vnum, int recStart=0, int recEnd =-1);
   QdObject_var QieText_to_Attr(QieVariable &V, std::string valueStr);
   QdObject_var QieText_to_Obj(QieVariable &V, std::string valueStr);
   int readDataRecords();
   bool parseLine(string &nextLine);
   bool findEntries();
   bool getEntriesChar(int nStart, int nEntries, int recNum, QdSMatrixSeq_var obj);
   bool getEntriesChar(int nStart, int recNum, QdStringSeq_var obj);
   bool getEntriesNumeric(int nStart, int nEntries, int recNum, QdRMatrixSeq_var ms);
   bool getEntriesNumeric(int nStart, int recNum, QdRScalarSeq_var ss);
   bool getEntriesTime(int nStart, int recNum, QdTimeSeq_var ts);
   QdStringSeq_var parseEntries(std::string inputStr, const char data_delim);
   bool initSequence(QieVariable * V, int nRecs);
   bool getVarRecordEntry(int nToGet, int recNum);
   void attachXrefs(QieVariable *V);
   void ensureDependZero();
   // Public interface to completed QieData object
   int  findVarNumByName(const char VorG, const char * name);
   void clearGetThis();
   void setGetThis(int vnum);
   QdTimeSeq_var getTTobj(int vnum); 
   // CDF methods
   bool queryCDFfile(const char * fullName);
   bool getCDFvariables(int n_vars);
   QieVariable getCDFVar(int nvar);
   void addVarAttrs(QieVariable &V, int nvar);
   void getCDFglobals();
   QdObject_var getGlobalAttr();
   void getCDFvarDataList(vector <int> getList, int recStart, int recEnd);
   void getCDFvarData(int nvar, int recStart, int recEnd);
   void convertCDFbufferToObj(int vnum, int seq_size, long data_type, int strLength, void *data);
   void convertCDFbufferToSingleObj(int vnum, long data_type, int strLength, void *data);
   void fixThemisEpoch(vector <int> getList);
   void getAttributeHelper(const char * fullName);
   void readAttrHelper();
   
   vector <QieVariable>  QieVars;   
   vector <QdObject_var> QieGlobals;
   vector <string> dataRecords;
   string currentRecord;
   int time_var_num;     // used only to find first timelike object in file in case DEPEND_0 missing
   QieFile inFile;
   QieFile outFile;
   QieFile attrFile;
   long year_offset;
   bool strictMonotonic;
   long yp_last;
   std::string parameter;
   std::string value;
   bool debug_on;
   FILE * fp_display;
   int recordNumEntries;
   vector <int> tokenStart;
   vector <int> tokenLen;
   int maxCDFnumRecs; // used for cdf as we leave data in file until needed. Vars may have fewer recs.

protected:

private:

	   
};

// Utility Functions
// -------------------------

void  QieMsg(const char *status, const char *line1, const char *line2 = NULL,  const char *line3 = NULL);
vector <std::string> QieFindHelperFiles(const char * dataFile, const char * dotExtn);
bool  QieStrIsNULL(const char *txt);
std::string QieStripQuotes(std::string value);
const char * QieToUpper(const char *txt);
char QieGetDelim (std::string value);
bool QieIsISOtime(std::string TestStrISO);
bool QieIsNumber(std::string ptr);
std::string QieSafePath(const char * path);
std::string QieUserHomeDir(const char * user_id);
void setDebug(bool d_on);
void setDebugDisplay(const char * displayPath);
void initDebug();
void *QdaAttrEntryMalloc( long num_elems, long data_type );
QdObject_var QdaCDFattrBufferToObj(void *data, int data_type, int num_elems);
bool cefWrite2 (int set);
bool cefRead2 (int set);

#endif
