//
//  Time.h
//
//  Qdos - time and time interval object classes
//
//  David Burgess
//  July 1999
//

#ifndef QDOS_TIME_H
#define QDOS_TIME_H

#include <string>
#include <vector>
#include <iostream>
#include <iomanip>
#ifdef HAVE_SSTREAM_H
#include <sstream>
#else
#include <strstream>
#endif
#include <algorithm>

#include "Std.h"
#include "Viostream.h"
#include "Adapter.h"
#include "QObject.h"
#include "Sequence.h"

// for time_h and (2) time for obtaining unix time
#include <time.h>

namespace QDOS {

class TimeException: public Exception {
public:
  TimeException( ExceptionMsg m ) : Exception(m<<"[TimeException]"){;} };
class BadTime : public TimeException {
public:
  BadTime( ExceptionMsg m = "" ) : TimeException(m<<" [BadTime]"){;}};
class BadTimeIntervalOption : public TimeException {
public:
  BadTimeIntervalOption( ExceptionMsg m = "" )
   : TimeException(m<<" [BadTimeIntervalOption]"){;}};

class Time;
Vostream& operator<<(Vostream&,const Time&);
Vistream& operator>>(Vistream&,Time&);

// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ class Time

// Date and time
// Time : representation is Julian 2000/1000 i.e. seconds since Julian 2000
//-------------------------------------------------------------------------
class Time
{
  friend Vostream& operator<<(Vostream&,const Time&);
  friend Vistream& operator>>(Vistream&,Time&);
public:
 
// --- define type representation
  typedef double TRep;
  static int epoch;

  typedef enum MonthNamesOptionE
    { FULL, FULL_LC, FULL_UC, SHORT, SHORT_LC, SHORT_UC } MonthNamesOption;

protected:
  TRep _trep;       // TRep is Julian 2000 / 1000
  
  static int cdf_julian_day( int year, int month, int day ); // julian day 
                                                             // from 0AD 
  static bool is_leap_year( int year )
    { return ( year%4 == 0 && (year%100 != 0 || year%400 == 0) ); }
  static int leap_index( int year )
    { return is_leap_year(year)? 1:0; }
  
  static int qie_days_in_month[2][13];        // nb for these index 0 not used!
  static const char* month_names[13];      // January is index 1
  static const char* full_month_names[13];
  // Initialise from a TRep - time representation value 
  Time( const TRep& tval ) : _trep(tval) {;}  
  // --- set time using op=
  Time& operator=( TRep tval )
  {
  // set internal time rep e.g. seconds since 0AD as a double
    set_time_rep(tval);
    return *this;
  }    

public:

   // --- Constructor functions

  Time():_trep(0){;}
    // Copy Constructor
  Time( const Time& ttime ) : _trep(ttime._trep) {;}
  Time( const string& iso_time )
  { set_from_iso(iso_time);}                 // from string in ISO time format
  Time( int year, int month, int day,
         double hour=0.0, double min=0.0, double sec=0.0 ) // from y-m-d h:m:s
    { set_ymd( year, month, day, hour, min, sec ); }
    
   Time& operator=( const Time& ttime )
   {
   // assign from another Time
       set_time_rep(ttime.get_time_rep());
       return *this;
   }
   
   Time& operator=( const string& time )
   {
   // set from string in ISO time format
       set_from_iso(time);
   }
  
   // --- set from day of month, month of year, year, and h:m:s
   Time& assign_ymd( int year, int month, int day,
           double hour=0.0, double min=0.0, double sec=0.0 );
   Time& set_ymd( int year, int month, int day,
           double hour=0.0, double min=0.0, double sec=0.0 )
   { assign_ymd( year, month, day, hour, min, sec ); }
           
   // --- set from day of year, year, and h:m:s
   Time& assign_ydoy( int year, int doy,
            double hour=0.0, double min=0.0, double sec=0.0 );
   Time& set_ydoy( int year, int doy,
            double hour=0.0, double min=0.0, double sec=0.0 )
   { assign_ydoy( year, doy, hour, min, sec ); }

   Time& set_from_iso( const string& iso_string ); // set from ISO string
   
   Time& set_current_time()
   { 
     time_t ltime;
     time(&ltime);
     tm *t=localtime(&ltime);
     assign_ymd(t->tm_year+1900,t->tm_mon+1,t->tm_mday,t->tm_hour,t->tm_min,\
       t->tm_sec);
     return *this;
   }

   Time& set_today()
   {
     time_t ltime;
     time(&ltime);
     tm *t=localtime(&ltime);
     assign_ymd(t->tm_year+1900,t->tm_mon+1,t->tm_mday);
     return *this;
   }
   
   // --- identity and negation operators
    Time operator+() const { return Time(get_time_rep());}
    Time operator-() const { return Time(-get_time_rep());}
  
  
   // --- add and subtract time
   Time operator+(const Time& ttime) const
   {
       Time tres=*this;
       tres.set_time_rep(tres.get_time_rep()+ttime.get_time_rep());
       return tres;
   } 
   Time operator-(const Time& ttime) const
   {
       Time tres=*this;
       tres.set_time_rep(tres.get_time_rep()-ttime.get_time_rep());
       return tres;
   }
   
   // --- multiply  time by some factor
   Time operator*(const TRep& tfact) const
   {
       Time tres=*this;
       tres.set_time_rep(tres.get_time_rep()*tfact);
       return tres;
   }
   
   Time operator*(const Time& ttime) const
   { return(*this)*ttime.get_time_rep();}

   // --- divide time by some factor
   
   Time operator/(const TRep& tfact) const
   {
       Time tres=*this;
       tres.set_time_rep(tres.get_time_rep()/((tfact!=TRep(0))?tfact:TRep(1)));
       return tres;
   }
   
   TRep operator/(const Time& ttime) const
   { return ((*this)/ttime.get_time_rep()).get_time_rep(); }
       
   // --- add and subtract time and update
   Time& operator+=(const Time& ttime )
   {
       set_time_rep(get_time_rep()+ttime.get_time_rep());
       return *this;
   }
   
   Time& operator-=(const Time& ttime)
   {
       set_time_rep(get_time_rep()-ttime.get_time_rep());
       return *this;
   }
   
   // --- shift Time
   Time& operator>>(const Time& ttime)
   {
     *this += ttime;
     return *this;
   }

   Time& operator<<(const Time& ttime)
   {
     *this -= ttime;
     return *this;
   }
   
   // --- multiply and divide by some factor and update
   Time& operator*=(const TRep& tfact) 
   {
       set_time_rep(get_time_rep()*tfact);
       return *this;
   }
   
   Time& operator*=(const Time& ttime) 
   { return (*this)*=ttime.get_time_rep();}
   
   Time& operator/=(const TRep& tfact) 
   {
       set_time_rep(get_time_rep()/((tfact!=TRep(0))?tfact:TRep(1)));
       return *this;
   }
   
   // --- logical operators
   bool operator==(const Time& ttime) const
   { 
        return (get_time_rep()==ttime.get_time_rep());
   } 
   
   bool operator!=(const Time& ttime) const
   { 
        return !(*this==ttime);
   } 
   
   bool operator<(const Time& ttime) const
   { 
        return (get_time_rep()<ttime.get_time_rep());
   }
   
   bool operator>=(const Time& ttime) const
   { 
        return !(*this<ttime);
   }  
   
   bool operator>(const Time& ttime) const
   { 
        return (get_time_rep()>ttime.get_time_rep());
   }
   
   bool operator<=(const Time& ttime) const
   { 
        return !(*this>ttime);
   }  
       
// not sure about meaning of friend operators defined in class ??
   
   friend Time operator*(const TRep& tfact,const Time& ttime)
   {
       return ttime*tfact;
   }

   friend Time abs(const Time& t) 
   {
       TRep val=t.get_time_rep();
       if (val<0)
           val=-val;
       return Time(val);
   }
   
   // --- date & time representations
   string iso( const string& t_str=" ",const string& z_str="") const 
   {return iso_srep(t_str,z_str); } // ISO xxxxx string 
                                                  // representation
   string iso_srep( const string& t_str=" ",const string& z_str="") const; 

// split date/time string representation into vector of strings
// [0]: year eg "1958" (4 digits)
// [1]: day of year eg "060" (3 digits)
// [2]: month of year eg "03" (3 digits)
// [3]: month full name eg "March"
// [4]: month short name eg "Mar"
// [5]: day of month eg "02" (2 digits)
// [6]: hour of day eg "12" (2 digits)
// [7]: minute of day eg "27" (2 digits)
// [8]: second of day "57"  (2 digits)
// [9]: millisecond of day eg "284"  (3 digits)

   void split_srep( vector<string>& str_components ) const;
   
   void split_dhms( int& d, int& h, int& m, double& s ) const;

//   string& month_name_str(string& string_rep,MonthNamesOption option=SHORT);
   
   // --- accessor function
   TRep get_time_rep() const { return _trep;}
   void set_time_rep(const TRep& tsec) { _trep=tsec;}
   
  double second_of_day( void ) const;
  double day_of_year( void ) const;
 
  void split_ymd( int& year, int& month, int& day ) const;
  void split_ymd( int& year, int& month, int& day,
                   int& hour, int& min, int& sec, int& msec ) const;
  void split_ymd( int& year, int& month, int& day,
                   int& hour, int& min, double& sec ) const;
  void split_ymd( int& year, int& month, int& day,
                   int& hour, int& min, float& sec ) const;
                   
  void split_ydoy( int& year, int& doy ) const;
  void split_ydoy( int& year, int& doy,
                    int& hour, int& min, int& sec, int& msec ) const;
  void split_ydoy( int& year, int& doy,
                    int& hour, int& min, double& sec ) const;
  void split_ydoy( int& year, int& doy,
                    int& hour, int& min, float& sec ) const;
  void display() const
  {
       cout << setw(17) << get_time_rep() << " " << iso_srep() << endl;
  }

};
// ----------- End of class Time -------------------
inline Vostream& operator<<(Vostream& v_os,const Time& t)
{ 
   double d=t.get_time_rep();
   v_os << d;
   return v_os;
}

inline Vistream& operator>>(Vistream& v_is,Time& t)
{
   double d;
   v_is >> d;
   t.set_time_rep(d);
   return v_is;
}

// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ class QdTime

class QdTime : public QdObject, public Time
{
public:
// Initialise from a TRep - time representation value 
//   - default constructor has tval zero
  QdTime( const Time::TRep& tval = 0 ) : Time(tval) {;}  
// Copy Constructor
  QdTime( const Time& ttime ) : Time(ttime.get_time_rep()) {;}
  QdTime( const QdTime& ttime ) : Time(ttime) {;}
// from string in ISO time format
  QdTime( const string& iso_time ) : Time( iso_time ) {;}
// from y-m-d h:m:s
  QdTime( int year, int month, int day,
         double hour=0.0, double min=0.0, double sec=0.0 ) 
    : Time( year, month, day, hour, min, sec ) {;}
    
  QdTime& operator=(const Time& t_new)
  { Time& t_old=*this; t_old=t_new; return *this;}
    
  virtual QdObject_var create() const
  { return new QdTime;}
  
  virtual QdObject_var copy() const
  { return new QdTime(*this);}
  
  virtual string srep(const StringRep& stringrep,int sequence_index=0) const
  { string t_str(stringrep.get_token(StringRep::SR_TOKEN_TIME_SEPARATOR));
    string z_str(stringrep.get_token(StringRep::SR_TOKEN_TIME_TRAILING_CHAR));
    return iso_srep(t_str,z_str);
  }
    
  virtual string object_srep(const StringRep& stringrep) const
  { return "QdTime";}

  virtual void get(Vistream& v_is)
  { Time& t=*this; v_is >> t;}

  virtual void put(Vostream& v_os)
  { const Time& t=*this; v_os << t;}

  QDOBJECT
 
};

typedef Var<QdTime> QdTime_var;
class TimeInterval;
Vostream& operator<<(Vostream&,const TimeInterval&);
Vistream& operator>>(Vistream&,TimeInterval&);


// ++++++++++++++++++++++++++++++++++++++++++++++++++++ class TimeInterval

class TimeInterval 
{
  friend Vostream& operator<<(Vostream&,const TimeInterval&);
  friend Vistream& operator>>(Vistream&,TimeInterval&);
public:
    typedef enum Sense_e {TIME_SENSE_NEGATIVE,NO_TIME_SENSE,
        TIME_SENSE_POSITIVE} Sense;
    typedef enum SetOption_e { START_TIME, END_TIME, CENTER_TIME,
        CENTRE_TIME=CENTER_TIME,
        SAME_START_TIME, SAME_END_TIME, SAME_CENTER_TIME, SAME_DURATION }
        SetOption;

private:
    Time _t1;
    Time _t2;

public:

    // --- Constructors
    TimeInterval():_t1(Time()),_t2(Time()){;}
    TimeInterval( const TimeInterval& tint): _t1(tint._t1),_t2(tint._t2)\
        {;}
    TimeInterval( const Time& st, const Time& ed,\
                Sense option=NO_TIME_SENSE )
    {
        set(st,ed,option);
    }
    
    // --- get start/end 
    
    Time start() const { return _t1;}
    Time end() const { return _t2;}
    Time start_abs() const { return std::min(_t1,_t2);}
    Time end_abs() const { return std::max(_t1,_t2);}  
    
    // --- get duration 
    
    Time duration() const { return _t2-_t1;}
    Time duration_abs() const {return end_abs() - start_abs();}
       
    // NB TimeInterval ti=...;
    // QSeconds(ti.duration());  ...is interval in seconds...    
   
    // --- get sense of time direction:  
    // +1 if start<end, -1 if end<start, 0 if start==end
    Sense get_sense() const
    {
      if (_t1<_t2)
        return TIME_SENSE_POSITIVE;
      else if(_t1>_t2)
        return TIME_SENSE_NEGATIVE;
      else
        return NO_TIME_SENSE;
    }         

    // --- set by operator=
    TimeInterval& operator=( const TimeInterval& tint )
    {
        set(tint.start(),tint.end());
        return *this; 
    }

    // --- set start and end; default option is NO_TIME_SENSE i.e. store
    // start as _t1, end as _t2 regardless of whether _t1>_t2 or _t2<_t1 
    // TIME_SENSE_NEGATIVE: force _t1>=_t2
    // TIME_SENSE_POSITIVE: force _t1<=_t2
    void set( const Time& st, const Time& ed,\
              Sense option=NO_TIME_SENSE)
    {
        switch(option)
        {
            case NO_TIME_SENSE:
                _t1=st;
                _t2=ed;
                break;
            case TIME_SENSE_NEGATIVE:
                _t1=std::max(st,ed);
                _t2=std::min(st,ed);
                break;
            case TIME_SENSE_POSITIVE:
                 _t1=std::min(st,ed);
                 _t2=std::max(st,ed);
         }
     }  
              
    
    // --- force ordering of start and end to be positive
    void force_sense( Sense option=TIME_SENSE_POSITIVE )
    {
         switch(option)
         {
             case TIME_SENSE_POSITIVE:
             if (_t1>_t2)
                 reverse();
             break;
             case TIME_SENSE_NEGATIVE:
             if (_t1 < _t2)
                 reverse();
             break;
             case NO_TIME_SENSE:
             break;
         }
    }
    
    // --- set start time (_t1) : options are
    // SAME_END_TIME : preserve end time, changing duration
    // SAME_DURATION : preserve duration, changing end time
    // SAME_CENTER_TIME : preserve _t1+ (_t2 - _t1)/2 i.e. change end_time
    // and duration
    void set_start( const Time& st, SetOption option=SAME_END_TIME)
    {     
        Time ttemp;
             
        switch(option)
        {
            case SAME_DURATION:
                _t2=st+_t2-_t1;
            break;
            case SAME_CENTER_TIME:
                ttemp=_t1+0.5*(_t2-_t1);
                _t2=st+2*(ttemp-st);
            break;
            case SAME_END_TIME:
            break;
            default:
            // Domain Error if any other option
            break;
            
        }
         
        _t1=st;
    }     
    
     
    //  --- set end time (_t2): options are
    // SAME_START_TIME : preserve start time, changing duration
    // SAME_DURATION : preserve duration, changing start time
    // SAME_CENTRE_TIME : preserve _t2 + (_t1 - _t2)/2 i.e.change start_time
    // and duration
    void set_end( const Time& ed, SetOption option=SAME_START_TIME )
    {
        Time ttemp;
        switch(option)
        {
            case SAME_DURATION:
                _t1=ed+_t1-_t2;
            break;
            case SAME_CENTER_TIME:
                ttemp=_t2+0.5*(_t1-_t2);
                _t1=ed+2*(ttemp-ed);
            break;
            case SAME_START_TIME:
            break;
            default:
            // Domain Error if any other option
            break;
        }
        _t2=ed;
    }     
    
    
    // --- set (signed ) duration in terms of other time units
    //     (seconds,minutes,hours,days)
    void set_duration(const Time& d, SetOption option=SAME_START_TIME);

    // --- set (signed) duration of interval, relative to a given 
    //     time with the time interpreted (by option) as the start, end or 
    //     centre time
    void set_duration( const Time& t, const Time& d,
                       SetOption option=START_TIME);

    // --- reverse start and end
    void reverse()
    {
        Time ttemp=_t1;
        _t1=_t2;
        _t2=ttemp;
    }

    // shift interval by given amount of time
    TimeInterval& operator>>(const Time& ttime)
    {
        _t1+=ttime;
        _t2+=ttime;
        return *this;
    }
        
    TimeInterval& operator<<(const Time& ttime)
    {
        _t1-=ttime;
        _t2-=ttime;
        return *this;
    }

    void shift_forward( double factor = 1.0 )
      { *this >> factor*duration(); }
    void shift_back( double factor = 1.0 )
      { *this << factor*duration(); }

    // --- Set Operations
    TimeInterval int_intersect(const TimeInterval& ti) const;
    TimeInterval int_union(const TimeInterval& ti) const;

    bool contains( const Time& t ) const;
    bool empty() const { return _t1==_t2;}

    
    // --- Logical Operations
    bool operator==(const TimeInterval& ti) const
    {
        return (start()==ti.start() && end()==ti.end());
    }
    
    bool operator!=(const TimeInterval& ti) const
    {
        return !(*this==ti);
    }
    
    string iso_srep(const string& t_str=" ",const string& z_str="") const
    { return start().iso_srep(t_str,z_str) + " - " + end().iso_srep(t_str,z_str);}

    void display() const
    {
        cout << "Interval start:";
        start().display();
        cout << "Interval   end:";
        end().display();
    }
};

inline Vostream& operator<<(Vostream& v_os,const TimeInterval& tint)
{ v_os << tint._t1; v_os << tint._t2; return v_os;}

inline Vistream& operator>>(Vistream& v_is,TimeInterval& tint)
{ v_is >> tint._t1; v_is >> tint._t2; return v_is;}

// +++++++++++++++++++++++++++++++++++++++++++ class TimeIntervalObject

class QdTimeInterval : public QdObject, public TimeInterval
{
public:
    QdTimeInterval() : TimeInterval() {;}
    QdTimeInterval( const TimeInterval& tint) : TimeInterval( tint ) {;}
    QdTimeInterval( const QdTimeInterval& tint) : TimeInterval( tint ) {;}
    QdTimeInterval( const Time& st, const Time& ed,
                      Sense option=NO_TIME_SENSE ) 
      : TimeInterval( st, ed, option ) {;}
      
    QdTimeInterval& operator=( const TimeInterval& tint_new )
    { TimeInterval& tint_old=*this; tint_old=tint_new;return *this;}
      
    virtual QdObject_var create() const
    { return new QdTimeInterval;}
    
    virtual QdObject_var create_elt() const
    { return new QdTime;} 
      
    virtual QdObject_var copy() const
    { return new QdTimeInterval(*this);}
    
    virtual string srep(const StringRep& stringrep,int sequence_index=0) const
    { string t_str(stringrep.get_token(StringRep::SR_TOKEN_TIME_SEPARATOR));
      string z_str(stringrep.get_token(StringRep::SR_TOKEN_TIME_TRAILING_CHAR));
      return iso_srep(t_str,z_str);
    }
    
    virtual string object_srep(const StringRep& stringrep) const
    { return "QdTimeInterval";}
 
    virtual void get(Vistream& v_is)
    { TimeInterval& tint=*this; v_is >> tint;}

    virtual void put(Vostream& v_os)
    { const TimeInterval& tint=*this; v_os << tint;}

    QDOBJECT
};

typedef Var<QdTimeInterval> QdTimeInterval_var;

// +++++++++++++++++++++++++++++++++++++++ class TimeIntervalSeq

//-------------------------------------------------------------------------

class TimeIntervalSeq : public Sequence<TimeInterval>
{
    public:
        
        TimeIntervalSeq(int num=0) : Sequence<TimeInterval>(num) {}
        TimeIntervalSeq(int num, const TimeInterval& val) : Sequence<TimeInterval>(num, val){}
        TimeIntervalSeq(const TimeIntervalSeq& seq) : Sequence<TimeInterval>(seq) {}
        TimeIntervalSeq(const vector<TimeInterval>& vec) : Sequence<TimeInterval>(vec) {}
        
        TimeIntervalSeq& operator=(const vector<TimeInterval>& vec)
        {
            TimeIntervalSeq& seq=*this; seq=vec; return *this;
        }
        
        TimeIntervalSeq& operator=(const TimeInterval& interval)
        {
            assign(this->size(), interval); return *this;
        }
};

class QdTimeIntervalSeq : public QdObject, public TimeIntervalSeq
{
    public:
        QdTimeIntervalSeq(int num=0) : TimeIntervalSeq(0) {}
        QdTimeIntervalSeq(int num, const TimeInterval& val) : TimeIntervalSeq(num, val) {}
        QdTimeIntervalSeq(const QdTimeIntervalSeq& seq) : TimeIntervalSeq(seq) {}
        QdTimeIntervalSeq(const vector<TimeInterval>& vec) : TimeIntervalSeq(vec) {}
        
        QdTimeIntervalSeq& operator=(const vector<TimeInterval>& vec)
        {
            QdTimeIntervalSeq& seq=*this; seq=vec; return *this;
        }
        
        QdTimeIntervalSeq& operator=(const TimeInterval& interval)
        {
            assign(this->size(), interval); return *this;
        }
        
        virtual bool is_sequence(void) const { return true; }
        
        int sequence_size(void) const { return size(); }
        
        virtual QdObject_var copy() const {return new QdTimeIntervalSeq(*this);}
        
        virtual QdObject_var create() const {return new QdTimeIntervalSeq;}
        
        virtual QdObject_var create_elt() const {return new QdTimeInterval;}
        
        virtual string srep(const StringRep& stringrep,int sequence_index=0) const
        {
            string s;
            if(sequence_index<0 || sequence_index>=size())
                return s;
            string t_str(stringrep.get_token(StringRep::SR_TOKEN_TIME_SEPARATOR));
            string z_str(stringrep.get_token(StringRep::SR_TOKEN_TIME_TRAILING_CHAR));
            return elt(sequence_index).iso_srep(t_str,z_str);
        }
        
        virtual string object_srep(const StringRep& stringrep) const
        { return "QdTimeIntervalSeq";}
        
        virtual void get(Vistream& v_is)
        { vector<TimeInterval>& tv=*this; v_is >> tv;}

        virtual void put(Vostream& v_os)
        { const vector<TimeInterval>& tv=*this; v_os << tv;}
        
        QDOBJECT
};

typedef SeqVar<QdTimeIntervalSeq> QdTimeIntervalSeq_var;

// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ class TimeSeq

//-------------------------------------------------------------------------

class TimeSeq : public NumericSequence<Time>
{
public:
  TimeSeq( int num=0 ) : NumericSequence<Time>(num) {;}
  TimeSeq( int num, const Time& val ) : NumericSequence<Time>(num,val) {;}
  TimeSeq( const TimeSeq& seq ) : NumericSequence<Time>(seq) {;}
  TimeSeq( const vector<Time>& vec ) : NumericSequence<Time>(vec) {;}
//  TimeSeq( const vector<double>& vec ) : NumericSequence<Time>() { 
//assign(vec);}

  TimeSeq& operator=(const vector<Time>& vec)
  { NumericSequence<Time>& timeseq=*this; timeseq=vec;return *this;}
 
  TimeInterval get_interval_bounds()
  {  return TimeInterval(min_value(),max_value());}

}; // end TimeSeq

class QdTimeSeq : public QdObject, public TimeSeq
{
  public:
  QdTimeSeq( int num=0 ) : TimeSeq(num) {;}
  QdTimeSeq( int num, const Time& val ) : TimeSeq(num,val) {;}
//  QdTimeSeq( const TimeSeq& seq ) : TimeSeq(seq) {;}
  QdTimeSeq( const QdTimeSeq& seq): TimeSeq(seq) {;}
  QdTimeSeq( const vector<Time>& vec ) : TimeSeq(vec) {;}
//  QdTimeSeq( const vector<double>& vec ) : TimeSeq() { assign( vec );}

  QdTimeSeq& operator=(const vector<Time>& vec)
  {TimeSeq& timeseq=*this; timeseq=vec;return *this;}
  
  virtual bool is_sequence(void) const { return true; }
  int sequence_size(void) const { return size(); }
  
  virtual QdObject_var create() const
  { return new QdTimeSeq;}
  
  virtual QdObject_var create_elt() const
  { return new QdTime;}
  
  virtual QdObject_var copy() const
  { return new QdTimeSeq(*this);}
  
  virtual string srep(const StringRep& stringrep,int sequence_index=0) const
  { string s;
    if(sequence_index<0 || sequence_index>=size())
        return s;
    string t_str(stringrep.get_token(StringRep::SR_TOKEN_TIME_SEPARATOR));
    string z_str(stringrep.get_token(StringRep::SR_TOKEN_TIME_TRAILING_CHAR));
    return elt(sequence_index).iso_srep(t_str,z_str);
  }
    
  virtual string object_srep(const StringRep& stringrep) const
  { return "QdTimeSeq";}
  
  virtual FunctionAdapter* multijoin(QdObjectSeq_var x_in, \
       QdObjectSeq_var y_in,QdObject_var x_out,QdObjectSeq_var y_out,\
       QdObjectSeq_var join_method,\
       QdObjectSeq_var gap_value, QdObjectSeq_var gap_handler,\
       int triage_cnt=-1) const
  { return new MultiJoinAdapter<Time>(x_in,y_in,x_out,y_out,\
           join_method,gap_value,gap_handler,triage_cnt);}

  virtual void get(Vistream& v_is)
  { vector<Time>& tv=*this; v_is >> tv;}

  virtual void put(Vostream& v_os)
  { const vector<Time>& tv=*this; v_os << tv;}

  QDOBJECT
}; // end QdosTimeSeq

typedef SeqVar<QdTimeSeq> QdTimeSeq_var;

class TimeUnitsOffset { public: static const double offset;};
class cdfEpochOffset { public: static const double offset;};

// ++++++++++++++++++++++++++++++++++++++++++++++++++++++ class TimeUnitsBase

//---------------------------------------------------------------------------
// Class TimeUnitsBase
// Template class for time units: Seconds, Minutes, Hours, Days
//
// These are utility classes so that one can forget about
// conversion between time units
//   Eg:  can write:
//        Time time_tag("23-nov-1998 12:00:00.0");
//        time_tag += Hours(5);
//    one can also combine time units objects ...
//        time_tag -= Days(2) - Hours(10)*1.2;
//
// Internal representation is defined by Time.
// Assignment and construction take into account
// a multiplicative factor mfac
// T is just the type for representation of value
// (will always be double?!)
//---------------------------------------------------------------------------
template <class T, class F, class O=TimeUnitsOffset>  
  class TimeUnitsBase : public Time
{
 public:
     // --- Constructors
     TimeUnitsBase(const T& value=0 ) : Time(value*F::mfac+O::offset) {;}
     TimeUnitsBase(const Time& t) : Time(t) {;}
     TimeUnitsBase(const TimeUnitsBase<T,F>& value ) : Time(value) {;}

     // --- Assign from another TimeUnitsBase
     TimeUnitsBase<T,F>& operator=(const TimeUnitsBase<T,F>& t)
     {
         set_time_rep(t.get_time_rep());
         return *this;
     }  
    // --- conversion to T e.g. returns no of hours as a T
    operator T() const {return (get_time_rep()-O::offset)/F::mfac; }
    void display() const
    {
        cout << "Time Units: " << T(*this) << endl;
        cout << "Internal Time Representation: ";
        Time::display();
    }    
};

// --- Interface types for time units
// for time since ..in seconds ... just Seconds(t2-t1) where t2 and t1 are 
// two Times 

class SecondsFactor { public: static const double mfac; };
class MinutesFactor { public: static const double mfac; };
class HoursFactor { public: static const double mfac; };
class DaysFactor { public: static const double mfac; };
class mSecondsFactor { public: static const double mfac; };

typedef TimeUnitsBase<Time::TRep,SecondsFactor> Seconds;
typedef TimeUnitsBase<Time::TRep,MinutesFactor> Minutes;
typedef TimeUnitsBase<Time::TRep,HoursFactor> Hours;
typedef TimeUnitsBase<Time::TRep,DaysFactor> Days;
typedef TimeUnitsBase<Time::TRep,mSecondsFactor> mSeconds;
typedef TimeUnitsBase<Time::TRep,mSecondsFactor,cdfEpochOffset> cdfEpoch;
typedef TimeUnitsBase<Time::TRep,SecondsFactor,cdfEpochOffset> cdfEpoch16;


inline ostream& operator<<( ostream& s, const Time& t )
{
  return s << t.iso_srep();
}

inline istream& operator>>( istream& is, Time& t )
{ string iso_time; is >> iso_time; t.set_from_iso(iso_time);return is;}

template<class F>
inline ostream& operator<<( ostream& os, \
    const TimeUnitsBase<QDOS::Time::TRep,F>& t )
{
  return os << (Time::TRep)t;
}


inline ostream& operator<<( ostream& s, const TimeInterval& tintvl )
{
  return s << tintvl.iso_srep(); 
}

} // end namespace QDOS

#endif // #ifndef QDOS_TIME_H



