// This may look like C code, but it is really -*- C++ -*-
// 
// <copyright> 
//  
//  Copyright (c) 1995
//  Institute for Information Processing and Computer Supported New Media (IICM), 
//  Graz University of Technology, Austria. 
//  
// </copyright> 
// 
// 
// <file> 
// 
// Name:        tiobr.h
// 
// Purpose:     
// 
// Created:     05 Dez 96   Till Vollmer
// 
// Modified:    
// 
// Description: 
// 
// $Id: tiobr.h,v 1.10 1997/02/21 16:17:13 jfasch Exp $
// 
// $Log: tiobr.h,v $
// Revision 1.10  1997/02/21 16:17:13  jfasch
// *** empty log message ***
//
// Revision 1.9  1997/02/21 16:16:19  jfasch
// egoist()
//
// Revision 1.8  1997/02/12 23:13:11  jfasch
// moved from HgDcCommon
//
// Revision 1.7  1997/01/13 11:42:00  jfasch
// oops
//
// Revision 1.6  1997/01/10 12:09:43  jfasch
// local verbose setting possible (yields version3)
//
// Revision 1.5  1997/01/08 13:41:25  jfasch
// some comment (test cases)
//
// Revision 1.4  1997/01/07 17:13:38  tvollmer
// new behavior inputReady()
//
// Revision 1.3  1997/01/07 17:13:00  tvollmer
// new behavior inputReady()
//
// Revision 1.2  1996/12/11 08:56:43  jfasch
// adapted to the new location (changed includes to be taken directly,
// etc.)
//
// Revision 1.1  1996/12/09 16:20:45  jfasch
// Initial revision
//
// Revision 1.2  1996/12/06 15:18:46  tvollmer
// first revision
//
// Revision 1.1  1996/12/06 14:30:43  tvollmer
// Initial revision
//
// 
// </file> 
#ifndef hg_dc_common_tiobr_h
#define hg_dc_common_tiobr_h

#include "tio.h"
#include "timerhandler.h"
#include "timerman.h"

#include <hyperg/utils/datalist.h>
#include <hyperg/utils/verbose.h>

// <class> 
//  
// Name:             
// 
// Purpose:          
// 
// Public Interface: 
// 
// Description:
//
// contains a TransparentIOPtr as the primary source of
// data. additionally, one may put data back in a stack-like
// manner. note that the TransparentIO scheme has to be maintained:
// registering for IO has to behave exactly the same as with normal
// TransparentIOs. i.e., the put back have to be served by callbacks
// if a reader is registered. 
//
// test cases: 
//
// - does writing work with and without a registered writer. the
// simplest thing because writing is promoted directly to the tio_.
//
// - does reading work without any data put back. the second simplest
// thing.
//
// - does reading work with put back data, and without a reader.
//
// - the same reader every time. he reads, having no put back data,
// and puts back some. does he get called afterwards? does he get the
// right data?
//
// - readers changing. one puts back, unregisters, another one comes
// along. does he get the right data, if any?
//
// - what else?
// 
// </class> 
class TransparentBReadIO : public TransparentIO, public TransparentIOHandler, protected TimerHandler
{
public:
   TransparentBReadIO(const TransparentIOPtr& tio) :timerisrunning_(false),tio_(tio)  {}
   virtual ~TransparentBReadIO() ;
   virtual void registerOutput (TransparentIOHandler*) ;
   virtual void registerInput (TransparentIOHandler*) ;
     
   virtual int  read (char*, int) ;
   virtual int  write (const char*, int) ;
   virtual void egoist (bool) ;

   virtual void putBack(const char*,int) ;

protected:
   virtual void inputReady (const TransparentIO*)  ;
   virtual void outputReady (const TransparentIO*) ;
    
   virtual void timerExpired (long, long) ;
    
private:    
   void startTimer_() ;
   void stopTimer_() ;

   bool timerisrunning_ ;
   TransparentIOPtr tio_ ;
   DataList datas_ ;
   TransparentIOHandler* handler_;
public:
   static Verbose verbose ;

   // link time assertion
   static const char* version3 ;
};
static const char* TransparentBReadIO_version = TransparentBReadIO::version3 ;


SmartPtrdeclare (TransparentBReadIOPtr,TransparentBReadIO) ;

inline void TransparentBReadIO::startTimer_()
{
    if (!timerisrunning_)
    {
        TimerManager::instance().startTimer(0,1,this) ;
        timerisrunning_ = true ;
    }
}

inline void TransparentBReadIO::stopTimer_()
{
    if (timerisrunning_)
    {
        TimerManager::instance().stopTimer(this) ; 
        timerisrunning_ = false ;
    }
}


#endif
