/* headers.h
 *             +--------------------------------------------------+
 *             | THIS FILE MUST MATCH headers.incp -> headers.inc |
 *             +--------------------------------------------------+
 *
 * Description:  C / C++ include of blue header
 *
 * Version: $Id: headers.h,v 1.7 2012/06/26 18:22:15 ntn Exp $
 */

#ifndef _HEADERS_H

#include "xmcompat.h"
#include "fcinterface.h"

#ifdef __cplusplus
#  include "utilities.hh"
#endif

#define L_quadwords   12
#define L_components  14
#define L_subrecords  26
#define L_outlets     8
#define L_keywords    92
#define L_header_size 1536

typedef struct {
  char  name[4];
  char  format[2];
  int_2 offset;
} SUBRECSTRUCT;

typedef struct {
  char  name[4];
  char  format[2];
  int_1 type;
  int_1 units;
} COMPSTRUCT;

typedef struct {
  real_8 xstart,xdelta;
  int_4  xunits,fill1;
  real_8 fill2,fill3;
  int_4 fill4;
  int_4 bid;		/* avl dr# 5349 buffer id */
} T1ADJUNCT;

typedef struct {
  real_8 xstart,xdelta;
  int_4  xunits,subsize;
  real_8 ystart,ydelta;
  int_4  yunits;
  int_4  bid;		/* avl dr# 5349 buffer id */
} T2ADJUNCT;

typedef struct {
  real_8 rstart,rdelta;
  int_4  runits,subrecords;
  real_8 r2start,r2delta;
  int_4  r2units,record_length;
  SUBRECSTRUCT subr[L_subrecords];
} T3ADJUNCT;

typedef struct {
  real_8 vrstart,vrdelta;
  int_4  vrunits,nrecords;
  real_8 vr2start,vr2delta;
  int_4  vr2units,vrecord_length;
} T4ADJUNCT;

typedef struct {
  real_8 tstart,tdelta;
  int_4  tunits,components;
  real_8 t2start,t2delta;
  int_4  t2units,record_length;
  COMPSTRUCT comp[L_components];
  real_8 quadwords[L_quadwords];
} T5ADJUNCT;

typedef struct {
  char FILL[160];
  FSTRING(frame_of_ref, 8);     /* coordinate reference frame */
  real_8 altitude;              /* altitude (meters) for topocent */
  real_8 latitude;              /* latitude (deg) for topocentric */
  real_8 longitude;             /* latitude (deg) for topocentric */
  real_8 azimuth;               /* azimuth (deg) for topocentric */
  real_8 elevation;             /* elevation (deg) for topocentric */
  real_8 roll;                  /* roll (deg) for topocentric */
  real_8 notused1;              /* */
  real_8 notused2;              /* */
  real_8 epoch_year;            /* year of epoch for ECI */
  real_8 epoch_seconds;         /* seconds of epoch for ECI */
  real_8 hour_angle;            /* GW angle (rad) at epoch f ECI */
} T5QUADSADJUNCT;

typedef union {
  char bytes[256];
  T1ADJUNCT t1;
  T2ADJUNCT t2;
  T3ADJUNCT t3;
  T4ADJUNCT t4;
  T5ADJUNCT t5;
  T5QUADSADJUNCT t5q;
} ADJUNCT;

typedef struct {
  FSTRING(        version, 4);  /* Header version */
  FSTRING(        head_rep, 4); /* Header representation */
  FSTRING(        data_rep, 4); /* Data representation */
  int_4           detached;     /* detached header */
#ifndef __cplusplus
  int_4           protected;    /* protected from overwrite */
#else
  int_4           protected_;   /* "protected" reserved to C++ */
#endif
  int_4           pipe;         /* pipe mode */

  int_4           ext_start;    /* extended header start block */
  int_4           ext_size;     /* extended header size bytes */
  real_8          data_start;   /* data start in bytes */
  real_8          data_size;    /* data size in bytes */

  int_4           type;         /* file type code */
  FSTRING(        format, 2);   /* data format code */
  int_2           flagmask;     /* 16 bit flag mask (1=flagbit) */
  real_8          timecode;     /* time code field */

  int_2           inlet;        /* inlet owner */
  int_2           outlets;      /* number outlets */
  int_4           outmask;      /* outlet async mask */
  int_4           pipeloc;      /* pipe location */
  int_4           pipesize;     /* pipe size in bytes */
  real_8          in_byte;      /* next input byte */
  real_8          out_byte;     /* next out byte (cumulative) */
  real_8          outbytes[L_outlets];  /* next out byte (each outlet) */

  int_4           keylength;            /* length of keyword string */
  char            keywords[L_keywords]; /* user defined keyword string */

  /* The following should be at offset 0x100 */
  ADJUNCT         adjunct;

  /* The following should be at offset 0x200 */
  FSTRING(        file_name, 80);    /* file name to/from M$ALLOCATE */
  FSTRING(        detach_name, 80);  /* file name for .det file */
  FSTRING(        type_allow, 40);   /* string of allowable type codes */
  FSTRING(        format_allow, 40); /* string of allow format codes */
  FSTRING(        qualifier, 40);    /* qualifier string */ /* TODO: this is 120 in XMC and XM44 */
  FSTRING(        label, 20);        /* filename result label */
  FSTRING(        rtype, 12);        /* file record type  */
  FSTRING(        switches, 8);      /* switch string, "switch" reserved to C/C++ */
  FSTRING(        extension, 4);     /* filename extension field */
  int_4           qualifierlen;      /* qualifier string length */
  int_4           file_lu;           /* file logical unit */
  int_4           head_lu;           /* file logical unit */
  bool_4          exist;             /* file existence flag */
  bool_4          open;              /* file open flag */
  bool_4          output;            /* open for output/input */
#ifndef __cplusplus
  int_4           class;             /* type code class (type/1000) */
#else
  int_4           class_;            /* "class" reserved to C++ */
#endif

  real_8          dbpe;         /* DP bytes per element */
  real_8          size;         /* file size in log elements */
  real_8          offset;       /* file read offset in log elem */
  real_8          save_offset;  /* byte offset of saved */
  real_8          first_byte;   /* data read first byte */
  real_8          last_byte;    /* data write last byte */

  int_4           bps;          /* bytes per scalar */
  int_4           spa;          /* scalars per atom */
  int_4           bpa;          /* bytes per atom */
  int_4           bpe;          /* bytes per element */
  int_4           ape;          /* atoms per element */
  int_4           save_size;    /* # elements in saved */
  int_4           savebuf_loc;  /* save buffer location (GRABX) */ /* TODO?: XM44: H_PTR */
  int_4           savebuf_len;  /* save buffer size in bytes */
  int_4           buffer_block;
  int_4           xfer_len;     /* transfer length */
  int_4           cons_len;     /* consume length */

  FSTRING(        scr_format,2);/* scratch format */
  char            buf_mode;     /* buffer format mode */
  char            buf_type;     /* buffer format type */

  bool_1          read_only;	/* "readonly" reserved on VMS systems */
  bool_1          overwrite;    /* open for over write ? */
  bool_1          contiguous;   /* open contiguous disk file ? */
  bool_1          flush;        /* keep output flushed to disk ? */

  int_4           outlet;       /* pipe outlet number */

  int_4           disk_blk;       /* disk address of file data */
  int_4           disk_blk_hdr;   /* disk address of file header */
  int_4           disk_blk_alloc; /* disk allocation of data */
  int_4           disk_address;   /* disk addr data in bytes */

  int_4           ext_loc;         /* ext header mem location */ /* TODO?: XM44: H_PTR */
  int_4           ext_alloc;       /* ext header mem allocated  */
  int_4           ext_scope_start; /* ext header scope start */
  int_4           ext_scope_end;   /* ext next offset */
  int_4           ext_next;        /* ext header scope end */

  int_2           last_bits;       /* bits in save_bits byte */
  int_1           save_bits;       /* holds packed offset byte */
  int_1           aux;             /* aux disk */

  int_4           lph; /* ID MAPPING TO DataFile OBJECT */
  int_4           blk;

  int_4           status;          /* DS status flag */
  int_1           mode;            /* DS IO mode */
  int_1           engine;          /* DS engine # */
  int_1           active;          /* DS active */
  int_1           dsfill;          /* DS filler */
  /* 512 bytes so far */

  H_PTR           t6subr_loc;      /* T6 subrecords mem location */
  int_4           t6subr_alloc;    /* T6 subrecords mem allocated */
  int_4           filler;          /* filler to 8 byte boundary (alignment) */

  int_1 ihdrfill[496];             /* fill internal header to 1024 */

  char            buffer[512];     /* primitive data buffer */

} HEADER;

typedef HEADER HEADERSTRUCT;		/* backwards compatibility */

/* Structure Def for Virtual recod buffer utilities */

#define		L_vrbhead	24
#define		L_keyhead	8

#define		MK_Normal	0
#define		MK_Main		1
#define		MK_Ext		2
#define		MK_Noscope	4
#define		MK_Next		8
#define		MK_Typeasis	16
#define		MK_Typetag	32
#define		MK_Replace	64
#define		MK_Index	128
#define		MK_Nextmatch	256
#define		MK_Last		512

#define		BK_Main		0
#define		BK_Ext		1
#define		BK_Noscope	2
#define		BK_Next		3
#define		BK_Typeasis	4
#define		BK_Typetag	5
#define		BK_Replace	6
#define		BK_Index	7
#define		BK_Nextmatch	8
#define		BK_Last		9

#define		VRB_INIT	1
#define		VRB_OFFSET	2
#define		VRB_READ	3
#define		VRB_WRITE	4

typedef struct {
  int_4 lkey;
  int_2 lext;
  char  ltag,type;
} KEYSTRUCT;

typedef struct {
  int_4 fsize,size;
  int_4	buf_loc,buf_len,record_len,next;
} VRBSTRUCT;
typedef VRBSTRUCT VRB;

/* M$HCBFUNC function masks */

#define	HCBF_CTG	1
#define	HCBF_AUX	2
#define	HCBF_SAM	4
#define	HCBF_FLUSH	8
#define	HCBF_APPEND	16
#define	HCBF_REOPEN	32
#define	HCBF_LASTBYTE	64
#define	HCBF_DETACH	128
#define	HCBF_INPUT	256
#define	HCBF_OUTPUT	512
#define	HCBF_HCBMOD	1024
#define	HCBF_OPTIONAL	2048
#define	HCBF_NOABORT	4096
#define	HCBF_PRESERVE	8192
#define	HCBF_WAIT	16384
#define	HCBF_EOF	32768
#define	HCBF_AVAIL	65536
#define	HCBF_SKIP	131072
#define	HCBF_PS 	262144

#ifdef __cplusplus

#include <cstring>  // for std::memset()

// DR 510049
inline void m_initialize (HEADER& hdr);

// This macro is for initializing all of the references in the
// CPHEADER class because it has to happen in both contructors.

#define CPHEADER_INIT_LIST \
      version(hcb.version), \
      head_rep(hcb.head_rep), \
      data_rep(hcb.data_rep), \
      detached(hcb.detached), \
      protected_(hcb.protected_), \
      pipe(hcb.pipe), \
      ext_start(hcb.ext_start), \
      ext_size(hcb.ext_size), \
      data_start(hcb.data_start), \
      data_size(hcb.data_size), \
      type(hcb.type), \
      format(hcb.format), \
      flagmask(hcb.flagmask), \
      timecode(hcb.timecode), \
      inlet(hcb.inlet), \
      outlets(hcb.outlets), \
      outmask(hcb.outmask), \
      pipeloc(hcb.pipeloc), \
      pipesize(hcb.pipesize), \
      in_byte(hcb.in_byte), \
      out_byte(hcb.out_byte), \
      outbytes(hcb.outbytes), \
      keylength(hcb.keylength), \
      keywords(hcb.keywords), \
      file_name(hcb.file_name), \
      detach_name(hcb.detach_name), \
      type_allow(hcb.type_allow), \
      format_allow(hcb.format_allow), \
      qualifier(hcb.qualifier), \
      label(hcb.label), \
      rtype(hcb.rtype), \
      switches(hcb.switches), \
      extension(hcb.extension), \
      qualifierlen(hcb.qualifierlen), \
      file_lu(hcb.file_lu), \
      head_lu(hcb.head_lu), \
      exist(hcb.exist), \
      open(hcb.open), \
      output(hcb.output), \
      class_(hcb.class_), \
      dbpe(hcb.dbpe), \
      size(hcb.size), \
      offset(hcb.offset), \
      save_offset(hcb.save_offset), \
      first_byte(hcb.first_byte), \
      last_byte(hcb.last_byte), \
      bps(hcb.bps), \
      spa(hcb.spa), \
      bpa(hcb.bpa), \
      bpe(hcb.bpe), \
      ape(hcb.ape), \
      save_size(hcb.save_size), \
      savebuf_loc(hcb.savebuf_loc), \
      savebuf_len(hcb.savebuf_len), \
      buffer_block(hcb.buffer_block), \
      xfer_len(hcb.xfer_len), \
      cons_len(hcb.cons_len), \
      scr_format(hcb.scr_format), \
      buf_mode(hcb.buf_mode), \
      buf_type(hcb.buf_type), \
      read_only(hcb.read_only), \
      overwrite(hcb.overwrite), \
      contiguous(hcb.contiguous), \
      flush(hcb.flush), \
      outlet(hcb.outlet), \
      disk_blk(hcb.disk_blk), \
      disk_blk_hdr(hcb.disk_blk_hdr), \
      disk_blk_alloc(hcb.disk_blk_alloc), \
      disk_address(hcb.disk_address), \
      ext_loc(hcb.ext_loc), \
      ext_alloc(hcb.ext_alloc), \
      ext_scope_start(hcb.ext_scope_start), \
      ext_next(hcb.ext_next), \
      ext_scope_end(hcb.ext_scope_end), \
      last_bits(hcb.last_bits), \
      save_bits(hcb.save_bits), \
      aux(hcb.aux), \
      lph(hcb.lph), \
      blk(hcb.blk), \
      status(hcb.status), \
      mode(hcb.mode), \
      engine(hcb.engine), \
      active(hcb.active), \
      dsfill(hcb.dsfill), \
      t6subr_loc(hcb.t6subr_loc), \
      t6subr_alloc(hcb.t6subr_alloc), \
      xstart(hcb.adjunct.t2.xstart), \
      xdelta(hcb.adjunct.t2.xdelta), \
      xunits(hcb.adjunct.t2.xunits), \
      subsize(hcb.adjunct.t2.subsize), \
      ystart(hcb.adjunct.t2.ystart), \
      ydelta(hcb.adjunct.t2.ydelta), \
      yunits(hcb.adjunct.t2.yunits), \
      bid(hcb.adjunct.t2.bid), \
      rstart(hcb.adjunct.t3.rstart), \
      rdelta(hcb.adjunct.t3.rdelta), \
      runits(hcb.adjunct.t3.runits), \
      subrecords(hcb.adjunct.t3.subrecords), \
      r2start(hcb.adjunct.t3.r2start), \
      r2delta(hcb.adjunct.t3.r2delta), \
      r2units(hcb.adjunct.t3.r2units), \
      record_length(hcb.adjunct.t3.record_length), \
      subr(hcb.adjunct.t3.subr), \
      vrstart(hcb.adjunct.t4.vrstart), \
      vrdelta(hcb.adjunct.t4.vrdelta), \
      vrunits(hcb.adjunct.t4.vrunits), \
      nrecords(hcb.adjunct.t4.nrecords), \
      vr2start(hcb.adjunct.t4.vr2start), \
      vr2delta(hcb.adjunct.t4.vr2delta), \
      vr2units(hcb.adjunct.t4.vr2units), \
      vrecord_length(hcb.adjunct.t4.vrecord_length), \
      tstart(hcb.adjunct.t5.tstart), \
      tdelta(hcb.adjunct.t5.tdelta), \
      tunits(hcb.adjunct.t5.tunits), \
      components(hcb.adjunct.t5.components), \
      t2start(hcb.adjunct.t5.t2start), \
      t2delta(hcb.adjunct.t5.t2delta), \
      t2units(hcb.adjunct.t5.t2units), \
      record_len(hcb.adjunct.t5.record_length), \
      comp(hcb.adjunct.t5.comp), \
      quadwords(hcb.adjunct.t5.quadwords), \
      frame_of_ref(hcb.adjunct.t5q.frame_of_ref), \
      altitude(hcb.adjunct.t5q.altitude), \
      latitude(hcb.adjunct.t5q.latitude), \
      longitude(hcb.adjunct.t5q.longitude), \
      azimuth(hcb.adjunct.t5q.azimuth), \
      elevation(hcb.adjunct.t5q.elevation), \
      roll(hcb.adjunct.t5q.roll), \
      epoch_year(hcb.adjunct.t5q.epoch_year), \
      epoch_seconds(hcb.adjunct.t5q.epoch_seconds), \
      hour_angle(hcb.adjunct.t5q.hour_angle)

// ///// CPHEADER Class

// The CPHEADER class provides a direct interface to the adjunct union
// data members fields of the HEADER struct (.xstart, .xdelta, etc.)
// and a constructor to automatically m_initialize() it (if desired).
// CPHEADER can also be wrapped around an existing HEADER when that
// HEADER is passed to its constructor.  This wrapper class makes
// accessing the HEADER very similar to how it would be accessed in
// FORTRAN.

class CPHEADER {

//    If this field is non-null, we allocated the memory associated
//    with the wrapped HEADER and need to delete it when we destruct.

    HEADER* adoptedHeader_;

  public:

    HEADER &hcb;

    fstring<4>   &version, &head_rep, &data_rep;
    int_4        &detached;
    int_4        &protected_;   // "protected" reserved to C++
    int_4        &pipe, &ext_start, &ext_size;
    real_8       &data_start, &data_size;
    int_4        &type;
    fstring<2>   &format;
    int_2        &flagmask;
    real_8       &timecode;
    int_2        &inlet, &outlets;
    int_4        &outmask, &pipeloc, &pipesize;
    real_8       &in_byte, &out_byte, *outbytes;
    int_4        &keylength;
    char         *keywords;
    fstring<80>  &file_name, &detach_name;
    fstring<40>  &type_allow, &format_allow;
    fstring<40>  &qualifier; // TODO: this is 120 in XMC and XM44
    fstring<20>  &label;
    fstring<12>  &rtype;
    fstring<8>   &switches;     // "switch" reserved to C/C++
    fstring<4>   &extension;
    int_4        &qualifierlen, &file_lu, &head_lu;
    bool_4       &exist, &open, &output;
    int_4        &class_;       // "class" reserved to C++
    real_8       &dbpe, &size, &offset, &save_offset, &first_byte, &last_byte;
    int_4        &bps, &spa, &bpa, &bpe, &ape;
    int_4        &save_size;
    int_4        &savebuf_loc;
    int_4        &savebuf_len; // TODO?: H_PTR in XM44
    int_4        &buffer_block;
    int_4        &xfer_len, &cons_len;
    fstring<2>   &scr_format;
    char         &buf_mode, &buf_type;
    bool_1       &read_only;
    bool_1       &overwrite, &contiguous, &flush;
    int_4        &outlet, &disk_blk, &disk_blk_hdr, &disk_blk_alloc;
    int_4        &disk_address;
    int_4        &ext_loc; // TODO?: H_PTR in XM44
    int_4        &ext_alloc, &ext_scope_start;
    int_4        &ext_next;
    int_4        &ext_scope_end;
    int_2        &last_bits;
    int_1        &save_bits, &aux;
    int_4        &lph;
    int_4        &blk;
    int_4        &status;
    int_1        &mode, &engine, &active, &dsfill;

    H_PTR        &t6subr_loc;
    int_4        &t6subr_alloc;

    // Type 1000/2000 adjunct
    real_8 &xstart, &xdelta;
    int_4 &xunits, &subsize;
    real_8 &ystart, &ydelta;
    int_4 &yunits, &bid;

    // Type 3000 adjunct
    real_8 &rstart, &rdelta;
    int_4 &runits, &subrecords;
    real_8 &r2start, &r2delta;
    int_4 &r2units, &record_length;
    SUBRECSTRUCT *subr;

    // Type 4000 adjunct
    real_8 &vrstart, &vrdelta;
    int_4 &vrunits, &nrecords;
    real_8 &vr2start, &vr2delta;
    int_4 &vr2units, &vrecord_length;

    // Type 5000 adjunct
    real_8 &tstart, &tdelta;
    int_4 &tunits, &components;
    real_8 &t2start, &t2delta;
    int_4 &t2units, &record_len;
    COMPSTRUCT *comp;
    real_8 *quadwords; // The first element in this array is frame_of_ref
    fstring<8> &frame_of_ref;
    real_8 &altitude, &latitude, &longitude;
    real_8 &azimuth, &elevation, &roll;
    real_8 &epoch_year, &epoch_seconds, &hour_angle;


    // ///// Methods

    // ///// Constructors/Destructor

    // Allocate our own header internally.

    CPHEADER (bool init = true) :
      adoptedHeader_(new HEADER),
      hcb(*adoptedHeader_),
      CPHEADER_INIT_LIST
    { if (init) initialize(); }

    // Take a reference to an existing HEADER structure and wraps it.
    // This is useful when another structure (like the VPHEAD
    // structure from the VPX option) has already allocated space for
    // the HEADER.

    CPHEADER (HEADER& header_ref, bool init = true) :
      adoptedHeader_(NULL),
      hcb(header_ref),
      CPHEADER_INIT_LIST
    { if (init) initialize(); }

    ~CPHEADER ()
    { if (adoptedHeader_) delete adoptedHeader_; }


    void initialize ()
    {
      // Zero out the header; X-Midas needs these fields to be
      // zeroed out, and they are not all fixed by M$INITIALIZE.
      std::memset(&hcb, 0, sizeof(HEADER));
      m_initialize(hcb);
    }

    // ///// Operators

    // Enable passing a CPHEADER where a HEADER is required

#ifndef __GNUG__
    operator HEADER& () { return hcb; }
    operator const HEADER& () const { return hcb; }
#else
    // Note that we do not provide the traditional const/non-const
    // pair of signatures when compiling with the GNU C++ compiler
    // because it issues a warning that cannot be quieted if it
    // encounters code that passes a non-const CPHEADER where a const
    // HEADER& is required.  In this situation the compiler could
    // choose to use either of the signatures above (it chooses the
    // first) and the C++ standard is not explicit about which it
    // should.  Until this is resolved we will have to sidestep the
    // compiler checking the const-ness of our arguments on GNU C++
    // when we are dealing with const CPHEADER instances.
    operator HEADER& () const { return hcb; }
#endif

  private:

    // Copy construction and assignment are intentionally not public
    // for fear that people will accidentally make copies without
    // meaning to do a true M$PROPAGATE.  Insist they be explicit.

    CPHEADER (const CPHEADER&);
    CPHEADER& operator= (const CPHEADER&);

}; // end class CPHEADER

// #undef CPHEADER_INIT_LIST

// HCB is an alias for CPHEADER.  CPHEADER is preferred.

typedef CPHEADER HCB;

#endif /* __cplusplus */

#define _HEADERS_H
#endif
