#ifndef SubRecord_HH
#define SubRecord_HH

#include <vector>

#include "SubHeader.hh"
#include "SubEventStatus.hh"


template <class Payload, unsigned NumberOfPayloads=1> class SubRecord
  : public SubHeader {

public:
  enum {
    trg=0x1000,
    emb=0x2000,
    ahc=0x3000,
    dhc=0x4000,
    bml=0x5000,
    slw=0x6000,
    daq=0x7000
  };

  SubRecord() : SubHeader() {
    set();
  }
  
  static unsigned subRecordTypeId();
  
  static const SubRecord<Payload,NumberOfPayloads>* safeCast(const SubHeader *h) {
    if(h==0 || h->subRecordType()!=subRecordTypeId()) return 0;
    return static_cast<const SubRecord<Payload,NumberOfPayloads>*>(h);
  }

  static SubRecord<Payload,NumberOfPayloads>* safeCast(SubHeader *h) {
    if(h==0 || h->subRecordType()!=subRecordTypeId()) return 0;
    return static_cast<SubRecord<Payload,NumberOfPayloads>*>(h);
  }

  /*
  static const Payload* safePayload(const SubHeader *h) {
    const SubRecord<Payload,NumberOfPayloads> *s(safeCast(h));
    if(s==0) return 0;
    else     return s->payload();
  }
  */

  static Payload* safePayload(const SubHeader *h) {
    const SubRecord<Payload,NumberOfPayloads> *s(safeCast(h));
    if(s==0) return 0;
    else     return s->payload();
  }

  static Payload* safePayload(SubHeader *h) {
    SubRecord<Payload,NumberOfPayloads> *s(safeCast(h));
    if(s==0) return 0;
    else     return s->payload();
  }

  static Payload* safeFirstPayload(RcdRecord *r) {
    SubHeader *h(0);
    for(h=r->firstSubHeader();h!=0;h=h->nextSubHeader()) {
      Payload *p(safePayload(h));
      if(p!=0) return p;
    }
    return 0;
  }

  static const Payload* safeFirstPayload(const RcdRecord *r) {
    const SubHeader *h(0);
    for(h=r->firstSubHeader();h!=0;h=h->nextSubHeader()) {
      const Payload *p(safePayload(h));
      if(p!=0) return p;
    }
    return 0;
  }

  static std::vector<const Payload*> safePayloadVector(const RcdRecord *r) {
    std::vector<const Payload*> v;
    const SubHeader *h(0);
    for(h=r->firstSubHeader();h!=0;h=h->nextSubHeader()) {
      const Payload *p(safePayload(h));
      if(p!=0) v.push_back(p);
    }
    return v;
  }

  static std::vector<Payload*> safePayloadVector(RcdRecord *r) {
    std::vector<Payload*> v;
    SubHeader *h(0);
    for(h=r->firstSubHeader();h!=0;h=h->nextSubHeader()) {
      Payload *p(safePayload(h));
      if(p!=0) v.push_back(p);
    }
    return v;
  }

  static Payload* safePayloadCreate(RcdRecord *r) {
    SubHeader* l(r->lastSubHeader());
    *l=SubHeader(subRecordTypeId(),NumberOfPayloads*sizeof(Payload));
    r->appendLastSubHeader(l);
    return safePayload(l);
  }

  static bool safePayloadAppend(RcdRecord *r, Payload *p) {
    Payload *q(safePayloadCreate(r));
    if(q==0) return false;

    *q=*p;
    return true;
  }



  void set() {
    subRecordType(subRecordTypeId());
    numberOfBytes(NumberOfPayloads*sizeof(Payload));
  }

  const Payload* payload(unsigned n=0) const {
    if(n>=NumberOfPayloads) return 0;
    return _payload+n;
  }

  Payload* payload(unsigned n=0) {
    if(n>=NumberOfPayloads) return 0;
    return _payload+n;
  }

  void payload(const Payload *p, unsigned n=0) {
    if(n<NumberOfPayloads) _payload[n]=*p;
  }

  void print(ostream &o) {
    SubHeader::print(o);
    o << std::endl;
    for(unsigned i(0);i<NumberOfPayloads;i++) {
      o << "  Payload " << i << " = " << _payload[i] << std::endl;
    }
  }

protected:
  Payload _payload[NumberOfPayloads];
};

template<> unsigned SubRecord<SubRunStatus,1>::subRecordTypeId() {
  return 1;
}
template<> unsigned SubRecord<const SubRunStatus,1>::subRecordTypeId() {
  return 1;
}
template<> unsigned SubRecord<SubConfigurationStatus,1>::subRecordTypeId() {
  return 2;
}
template<> unsigned SubRecord<const SubConfigurationStatus,1>::subRecordTypeId() {
  return 2;
}
template<> unsigned SubRecord<SubSpillStatus,1>::subRecordTypeId() {
  return 3;
}
template<> unsigned SubRecord<const SubSpillStatus,1>::subRecordTypeId() {
  return 3;
}
template<> unsigned SubRecord<SubEventStatus,1>::subRecordTypeId() {
  return 4;
}
template<> unsigned SubRecord<const SubEventStatus,1>::subRecordTypeId() {
  return 4;
}

#endif
