/****************************************************************************
 *   tseries.h : 
 *   		header file for time series class.
 *
 *   Change Log :
 *		 July-28-1997 Initial version,  Liujian Qian
 *
 *   $Id: gtseries.h,v 1.9 1999/02/03 07:41:25 qian Exp $
 ***************************************************************************/
 
#ifndef _TIMESERIES_H_
#define _TIMESERIES_H_

#include "gadt.h"
#include "gadt_time.h"

class GEpisode;

/**
 * @internal
 *
 *  GEpisodePool 
 *
 *
 *     THis class manages a pool of GEpisodes. This is meant to speed up
 *     the allocation/freeing of individual GEpisodes. The pool is 
 *     extended with POOL_DELTA structures of GEpisodes each time.
 *     It is a globaly shared pool.
 */
class GEpisodePool
{
    enum {POOL_DELTA = 400};
    
    static int 	  n_total;
    static int	  n_free;
    static GEpisode*   pool;
    
public:
    /**
     */
    ~GEpisodePool() {freeAll(); };
    
    /**
     * allocate an episode record from the pool
     */
    static GEpisode* 	allocEpisode();
    /**
     * free an episode record and put it back to the pool
     */
    static void		freeEpisode(GEpisode* ep);
    /**
     * extend the capacity of the pool w/ 'incr' of new episodes
     */
    static Result	extendPool(int incr=POOL_DELTA);
    /**
     * free all episodes; vacate the pool
     */
    static void		freeAll();

    static void		printStats (){
	cout<<"total episodes allocated: "
	    <<n_total<<", free episodes: "
	    <<n_free<<endl; 
    }
};


/**
 * @short  The unit of a time series.
 *
 *     This class represents  an episode (or an event) in a time series. 
 *     GEpisode is the unit of time series. Each episode has a timestamp 
 *     and an event descriptor which is not interpreted by this class. 
 */
class GEpisode : public GTimestamp
{
    char	evt_desc[8];
    GEpisode*	prev;	// for linking episodes
    GEpisode*	next;	

    friend class GEpisodePool;
    friend class GTimeSeries;
    
public:

    /**
     */
    GEpisode () :prev(0),next(0) { memset(evt_desc, 0, 8); }
    /**
     */
    GEpisode (const GDate& d) : GTimestamp(d) { memset(evt_desc, 0, 8); }
    /**
     */
    GEpisode (int year):GTimestamp(year), prev(0),next(0)  { memset(evt_desc, 0, 8); }
    /**
     */
    GEpisode (int year, int mon, int day, int hour=0, int min=0, int sec=0) 
	:GTimestamp(year, mon, day, hour, min, sec),  prev(0), next(0) 
          { memset(evt_desc, 0, 8); }
    GEpisode(const GEpisode& a);
    
    virtual ~GEpisode() {};
    

    // GROUP: GEpisode specific  methods.

    /**
     * return pointer to the next episode
     */
    GEpisode*	nextEpisode(void) const {return next; }
    /**
     * return previous episode (the one whose timestamp is smaller/earlier)
     */
    GEpisode*	prevEpisode(void) const {return prev; }

    /**
     * return the event descriptor; desc must be preallocated w/ >= 8 bytes.
     */
    char*	desc(void) {return evt_desc;}
    /**
     * set the event descriptor
     */
    void  	setDesc (const char* desc) {
	                                     if(!desc) { msgWarn("invalid evt desc!"); }
					     else memcpy(evt_desc, desc, 8); 
                                           }
    /**
     * set the specific date
     */
    void	setDate (int year, int mon, int day, int hour=0, int min=0, int sec=0);
    
    /**
     * set the timestamp
     */
    void	setTimestamp(const GTimestamp& st) { GTimestamp::operator=(st); };
    

    /**
     */
    void * operator new(size_t){ return GEpisodePool::allocEpisode();}
    /**
     */
    void  operator delete(void* ep, size_t){ GEpisodePool::freeEpisode( (GEpisode*)ep);}

    friend ostream& operator<<(ostream& o, const GEpisode& e);
};


/**
 * direction for scanning a time series
 */
enum TimeDir {FORWARD=0, BACKWARD=1};	


/**
 * @short GTimeSeries manages a time series.

      A time series is simply a list of episodes of (TIMESTAMP, EVENT_DESC),
      where the TIMESTAMP is the time an event of interest happened.
      The event here is a rather broad concept, it can be virtualy
      anything worthing recording. THe EVENT_DESC is a pointer (not the actual
      entity) to a record of the associated event. One
      use of the EVENT_DESC is to store an record ID of an externaly stored
      event.  But it is really an opaque data structure as far as time series
      is concerned.

      When the list of episodes are sorted (as they always are), the order
      is that  the older (earlier) the episode, the smaller the value.

      The main methods for GTimeSeries includes: inserting/deleting,
      iterating and generalizing the timestamps etc.
      When iterating the series, first call firstEpisode() or lastEpisode(),
      depending on which direction you want to scan the episodes, which
      will return a pointer to the correct episode; then call that episode's
      nextEpisode() or prevEpisode() correspondingly.

      Note: the time series stores only the pointer to episodes! So if you
            want to store two episodes, they must be physically different
	    objects (allocated using two new() opeations). If you just 
	    allocate one episode, and try to add two episodes to the series
	    by assigning two different timestamp to the same episode object,
	    it won't work! The doubly-linked list will be messed up if you
	    add the same objects twice!

	    Also note that it uses the GTimestamp class extensively, but
	    GTimeSeries isn't an ADT per se., aka, it can't be stored in a 
	    database.
*/
class GTimeSeries 
{
public:

    // GROUP:: ctor/dtor
    /**
     */
    GTimeSeries(TimeUnit u=_DAY): n_episodes(0), sorted(0), 
	first(0), t_unit(u), last_active(0) {};
    GTimeSeries& operator= (const GTimeSeries& a);
    
    /**
     */
    ~GTimeSeries();
    
    /**
     * set the unit time for the series
     */
    void	setTimeUnit(TimeUnit u) { t_unit=u;};
    /**
     * return the current time unit for the series
     */
    TimeUnit	timeUnit(void) const { return t_unit; }

    /**
     * add an episode into the series (in sorted order)
     */
    Result	addEpisode(GEpisode* r);
    /**
     * delete an episode from the series (and put back to the pool)
     */
    Result	delEpisode(GEpisode* r);
    /**
     * For every 'delta' time unit between  'from' (included) and 'to', 
     * generate an episode and add the episode to the series. The
     * newly added episodes will be in sorted order. 
     */
    Result	addRange(const GDate& from, const GDate& to, int delta=1);
    /**
     * same as above, except it accepts GTimestamps
     */
    Result 	addRange(const GTimestamp& begin, const GTimestamp& end, int delta=1);
    /**
     * delete all the episodes and reset to the new time unit if different
     */
    Result	reset(TimeUnit u=_INVALID);
    
    /**
     * return number of episodes in the series
     */
    int		numEpisodes(void) const {return n_episodes; }
    /**
     * return the first episodes in the series
     */
    GEpisode*	firstEpisode(void) const {return first; }
    /**
     * return the last episode (most recent one)
     */
    GEpisode*	lastEpisode(void) {return first->prev;};
    
    /**
     * generalize the series to a larger unit (eg, hours -> days)
     */
    Result	generalize(TimeUnit new_unit);
    /**
     * return true if the series is empty
     */
    bool        isEmpty(void) { return n_episodes==0; }

    friend ostream&    operator<<(ostream& os, const GTimeSeries& t);
    
private:
    
    Result	deleteAllEpisodes(void);

    friend class GTimeSeriesItr;    
    int 	n_episodes;
    short	sorted;		//0: not sorted; 1: ascend; 2:descend
    GEpisode*	first;		//first episode
    TimeUnit    t_unit;		//hours, days, months, years...
    GEpisode*	last_active;	//for speeding purpose (alwyas keep last
                                //active episode (the one last looked at, 
                                //just inserted, et al)
};


/**
       An iterator class for a time series object.

       This is the iterator class for the GTimeSeries class. It steps through
       individual episodes (either backwards or forwards).

*/
class GTimeSeriesItr
{
    GTimeSeries*	series;
    GTimestamp	starting;
    GEpisode	episode;
    TimeDir	dir;	//backward or forward
    int 	idx;
    bool	end;
    GEpisode	ep;
 
public:
    GTimeSeriesItr();
    GTimeSeriesItr(GTimeSeries* ser, TimeDir dir=FORWARD);
    GTimeSeriesItr(GTimeSeries* ser, GTimestamp& begin, TimeDir _dir=FORWARD);
    virtual ~GTimeSeriesItr() {}

    // GROUP: common iterating methods
    
    /**
     *  'what' to iterate on
     */
    virtual void    reset(const GADT* what=0) ;

    /**
     * true if have more elements.
     */
    virtual bool    more() const   ;

    /**
     * return next avialable episode
     */
    GEpisode&	    next() ;

    /**
     * set the series to iterate on
     */
    void	    seGTimeSeries(GTimeSeries* ser);
    /**
     * set the direction to iterate
     */
    void	    setDirection(TimeDir direction);
    /**
     * return the current iterating direction
     */
    TimeDir	    direction();
    
};

    
#endif





Documentation generated by lqian@lqian-sun on Wed Jul 14 09:36:10 EDT 1999