// Change History:
// 01/12/04 AV Development: Add AddAppl/RemoveAppl and GetStatus() to test whether Appl is a valid object. See bug #57
// 01/12/04 AV Development: Call to DRS_Terminate will delete Application pointer. Make sure appl has valid status. See bug #57
// 01/08/04 AV Development: Add RecordMacro/RunMacro/StopMacro/MacroProcess to fix bug #55
// 12/16/03 AV Development: Add process control functions. Process cache
// 12/10/03 AV Development: Remove SetRunningProcesses
// 11/20/03 AV Development: BC6 conversion. const/none const
// 8/19/03 AV Development: Merge: RecordRead
// 8/19/03 AV Development: Merge: VectorDatabase
// 8/19/03 AV Development: Remove: RecordSetFree
// 8/19/03 AV Development: Add: DeleteRecord(const AT_Record * Record)
// 8/27/03 AV Development: Add _spawn func to replace C library spawnl
// 10/23/03 AV Development: Add Macro def class

#ifndef AT_APPL_H
#define AT_APPL_H

//#include <cstring>
#include <vector>
#include <list>

#include  "base/at_defs.h"
#include  "xdart/x_at_reclist.h"
#include  "xdart/x_at_index.h"
#include  "xdart/x_at_data.h"
// #include  "data.h"
#include  "xdart/x_at_file.h"
// #include  "at_quantiles.h"
#include  "retrieve/at_retrieve.h"

#include  "drs/drs_type.h"
#include  "drs/drs_idx.h"
#include  "drs/drs_vect.h"
#include  "drs/drs_fld.h"
#include  "retrieve/collection.h"

class DRS_Application;
class DRS_Database;
class DRS_SearchField;
class DRS_IndexList;
class DRS_Index;
class DRS_Field;

class DRS_IndexFile
{
public:
  DRS_IndexFile( DRS_Database const &rParent, uint iIndexFileID);
  ~DRS_IndexFile();

  AT_Index                 IndexOpen( uint idx_id);
  AT_Quantile_List const & Quantile( int iQuantile);                 //Quantile
  inline uint              ID() const { return iIndexFileID;};
  bool operator!
    ()
    const;


private:
  AT_Index_List *  pAT_IndexList;
  uint             iIndexFileID;

  //Collection of AT_Quantiles. Opened and maintained on as-need basis
  class deleteList
  {
  public:
    void operator ()
      (AT_Quantile_List *ptr)
    { ARL_DeleteQuantileList(ptr); }
  };
  Collection<AT_Quantile_List, deleteList> collQuantiles;

  DRS_Database const &rDatabase; //Parent database ( location of files)
  AT_Read_Rand_File *p_dxfile;
  AT_Read_Rand_File *p_drfile;
};

////////////////////////////////////////////////////////
// DRS_Database classes
////////////////////////////////////////////////////////
class DRS_FieldDef;
class DRS_Vector;

class APPL_DECL DRS_Database
{
public:
  DRS_Database( DRS_Application const *pAppl, byte desig, uint id);
  ~DRS_Database();

  bool operator!
    ()
    const;

  inline byte                    Designator() const { return cDBDesig;};
  inline uint                    ID() const { return iID;};
  inline DRS_Application const & ParentAppl() const { return( rAppl);};
  inline AT_Database const     * CoreDatabase() const { return pDatabase;};
  inline uint                    RecordCount() const { return pDatabase->getRecordCount();};
  //Fields
  inline uint                    FieldCount() const { return iFieldCount;}
  //inline uint                    FieldCount() { return pDatabase->getFieldCount();};
  DRS_Field const &              Field( uint iField) const;

  uint                           DataFieldApplID( uint iFieldID) const;

  //Vectors
  inline uint                    VectorCount() const { return iVectorCount;}
  DRS_Vector const &             Vector( uint iVector) const;
  //Search fields
  inline uint                    SearchFieldCount() const { return iSearchFieldCount;}
  DRS_SearchField const &        SearchField( uint iFieldID) const;

  											//Database retrieves AT_Indexes from IndexFiles for SearchFields and vectors
  											//Vector indexes: may have to calculate IndexFile or IndexID
  AT_Index    							IndexOpen( uint iVectorID, int iIndexFileID, uint iIndexID);
  											//Search field indexes are absolute
  AT_Index    							IndexOpen( int iIndexFileID, uint iIndexID);

  											//Database retrieves AT_quantile_lists from IndexFile.
  AT_Quantile_List const & 		Quantile( int iIndexFileID, int iQuantileID);

  											//Database maintains master Vector
  											//DRS_Vector attaches at node of master
  inline uint 							VectorDepth() const { return (pDatabase->getVectorIDs());};
  inline uint 							VectorLength() const { return pDatabase->getPeriods();};


  inline uint                    FieldMapCount() const { return 0;}
  uint                           Version() const
    { return pDatabase ? pDatabase->getVersion() : 0; }
  
private:
  friend DRS_Application;

  //FieldMaps
  uint 											iFieldMapCount;
//  auto_array< auto_ptr<DRS_FieldMap> > FieldMaps;

  //Fields
  uint                                 iFieldCount;
  auto_array< auto_ptr<DRS_Field> >		 pFields; //array of DRS_Field *

  //Vectors
  uint 											iVectorCount;
  DRS_Vector **     						   Vectors;

  //Search fields
  uint16 											iSearchFieldCount;
  auto_array< auto_ptr<DRS_SearchField> > aaSearchFields;

  //IndexFiles
  //Database opens and maintains index list files for vectors and srchfields.
  //New vectors and srch fields rcv reference to parent db for index requests from
  //index lists.
  std::vector<DRS_IndexFile *> 				vIndexFiles;
  DRS_IndexFile & 								IndexFile( uint iIndexFileID);

  //Parent application
  DRS_Application const &						rAppl;

  //Database stuffums
  byte        										cDBDesig;
  uint        										iID;

  //Database & files
  AT_Database *									pDatabase;

  AT_Read_Rand_File *							pDTFile;
  AT_Read_Rand_File *							pDIFile;
  AT_Read_Rand_File *							pDDFile;
};

////////////////////////////////////////////////////////
// DRS_Application class
////////////////////////////////////////////////////////
class APPL_DECL DRS_Application
{
private:
  typedef void _stdcall DDP_SessionClose();
  DDP_SessionClose * CloseSession;
  
public:
  // Application Types

  //Field Types
  enum FieldType { DT_SCALAR, DT_VECTOR };
  
public:
  DRS_Application( char const *appl_id);   //Blank appl.
  DRS_Application( char const *appl_id, char const *ini_file);

  ~DRS_Application();

  // session callback
  void SetSessionClose( DDP_SessionClose * _close ) { CloseSession = _close; }
  
  const byte            * ID() const { return (const byte *)sApplID.c_str();}
  const byte            * Description() const { return (const byte *)sApplDescr.c_str(); }
  const byte            * INIFile() const { return (const byte *)sIniFile.c_str(); }
  const byte            * DataPath() const { return (const byte *)sDataPath.c_str(); }
  uint                    SearchFieldCount() const;
  DRS_SearchField const & SearchField( uint iSearchField) const;
  //int                     SearchFieldFieldMapID( uint iSearchField) const;

  uint                    FieldMapCount() const;
  // DRS_FieldMap const &    FieldMap( uint iFieldMap) const;

  uint                    FieldCount() const;
  DRS_Field const &       Field( uint iField) const;

  uint                    VectorCount() const;
  DRS_Vector const &      Vector( uint iVector) const;
  uint                    MaxVectorDepth() const;

  void                    RecordErrors( AT_Error &err);
  void                    RecordErrors( const byte * err) { vErrorStrings.push_back((char *)err); }
  string                  ExceptionPop();
  inline uint             ExceptionLen() { return vErrorStrings.back().length();};   //Length of last exception
  inline uint             ExceptionCount() { return vErrorStrings.size();};
  inline std::vector<string> const & Exceptions() { return vErrorStrings;};

  AT_Record_List * RecList_New();

  //Record sets. DRS_RecordSet contains i rec per db. Inited/freed by appl.
  AT_Record const ** RecordSetGet( uint32 lRecNo) const;  //Used by DRS_RecordSet. 1 rec/db
  AT_Record const * RecordGet( uint32 lRecNo, uint iDatabase) const; //Used to get record from a database
  bool              RecordRead( uint32 lRecNo, uint iDatabase, AT_Record * Rec) const {
    return aaDatabases[iDatabase].get()->pDatabase->readRecord( Rec, lRecNo); } //Used to read record from a database
  void              DeleteRecord(const AT_Record * Record) const;
  uint              RecordCount() const { DRS_Database * db = aaDatabases[0].get();
                                            return db ? db->pDatabase->getRecordCount() : 0;  }
  //Vector retrieval by occurrence
  uint VectorDatabase( uint iVectorIdx) const;
  uint32 RecordVectorCount( AT_Record const *AT_Records[], uint iVectorIdx) const;

  //Application file services
  static void DataFileAssert( byte *fp);
  static byte * DataFilePathGet( const byte *fn, byte *fp, uint size, const byte * ini);
  static byte * FormatApplID(const byte * in, byte * out);

  // validation
  bool operator!
  ();

  /* External database access for QC programm */
  inline uint             DatabaseCount() const { return iDatabaseCount; };
  inline DRS_Database const & Database( uint iDatabaseID) const { return *aaDatabases[iDatabaseID].get();};

  friend DRS_Database;

private:
  // helpers
  void         SetApplId(const byte * id);

  std::string                          sApplID;
  std::string                          sApplDescr;
  std::string                          sIniFile;
  std::string                          sDataPath;

  uint                                 iDatabaseCount;
  auto_array< auto_ptr<DRS_Database> > aaDatabases;

  bool                                 isLoaded;

  std::vector<string>                  vErrorStrings;
};

#endif

