// 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.C
// 
// Purpose:     
// 
// Created:     05 Dez 96   Till Vollmer
// 
// Modified:    
// 
// Description: 
// 
// $Id: tiobr.C,v 1.13 1997/02/21 16:18:02 jfasch Exp $
// 
// $Log: tiobr.C,v $
// Revision 1.13  1997/02/21 16:18:02  jfasch
// egoist()
//
// Revision 1.12  1997/01/16 15:57:18  gorasche
// added memory.h for memcpy prototype
//
// Revision 1.11  1997/01/13 11:41:35  jfasch
// *** empty log message ***
//
// Revision 1.10  1997/01/10 12:09:36  jfasch
// nothing
//
// Revision 1.9  1997/01/10 12:09:08  jfasch
// local verbose setting possible (yields version3)
//
// Revision 1.8  1997/01/09 08:50:14  jfasch
// rewrote parts to function correctly if put-back data exists, the
// reader gets notified, and does not read anything. he then got not
// notified again.
//
// Revision 1.7  1997/01/07 17:14:48  tvollmer
// new behavior inputReady()
//
// Revision 1.6  1996/12/18 15:19:22  jfasch
// bug fix: putting back (at least) 2 succeeding blocks failed completely
//
// Revision 1.5  1996/12/17 14:49:00  tvollmer
// bug removed: registerInput()
//
// Revision 1.4  1996/12/17 13:18:40  jfasch
// DEBUGNL
//
// Revision 1.3  1996/12/12 14:51:07  jfasch
// nothing important
//
// Revision 1.2  1996/12/11 08:56:33  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:38  tvollmer
// fisrt revision
//
// Revision 1.1  1996/12/06 14:30:55  tvollmer
// Initial revision
//
// 
// </file> 
#include <memory.h>

#include "tiobr.h"


#include <hyperg/utils/assert.h>
#include <hyperg/utils/new.h>
#include <hyperg/utils/verbose.h>

// --------------------------------------------------------------------
Verbose TransparentBReadIO :: verbose ;

const char* TransparentBReadIO::version3 ="TransparentBReadIO: $Id: tiobr.C,v 1.13 1997/02/21 16:18:02 jfasch Exp $" ;

TransparentBReadIO::~TransparentBReadIO()
{
    hgassert(!reader() && !writer(),"TransparentBReadIO::~TransparentBReadIO() reader or writer registered") ;
    stopTimer_() ;
}

void TransparentBReadIO::registerInput (TransparentIOHandler* hl) 
{
    DEBUGNL ("TransparentBReadIO::registerInput("<<hl<<')') ;
    if (hl==0)  // remove handler also from original
    {
        set_reader_(0);
        tio_.ptr()->registerInput(0) ;
        stopTimer_() ;
    }
    else
    {
        hgassert(!reader(),"TransparentBReadIO::registerInput(non-nil): already registered") ;
        set_reader_(hl) ;
        if (!datas_.count()) //  empty so register ourself
        {
            tio_.ptr()->registerInput(this) ;
        }
        else
        {
            // timer set to get it
            DEBUGNL ("TransparentBReadIO::registerInput(): setting timer") ;
            startTimer_() ;
        }
    }
}

int TransparentBReadIO::read (char* it, int size) 
{
    // lets read some stuff
    if (!datas_.count())  // normal read
    {
        hgassert(tio_.ok(),"TransparentBReadIO::read() no tio set") ; 
        return tio_.ptr()->read(it,size) ;
    }
    else
    {
        int consumed=0;
        // we have something buffered

        while (consumed<size && datas_.count())
        {
            DataPtr tmp=datas_.shift();
            if (tmp.ptr()->size()<=size-consumed)
            {
                ::memcpy(it+consumed,tmp.ptr()->raw(),tmp.ptr()->size());
                consumed += tmp.ptr()->size();
            }
            else
            {
                // put back the rest
                ::memcpy(it+consumed,tmp.ptr()->raw(),size-consumed);
                char* x = HGNEW(char[tmp.ptr()->size()-size+consumed]) ;
                memcpy(x,tmp.ptr()->raw()+size-consumed,tmp.ptr()->size()-size+consumed);
                datas_.unshift(DataPtr(HGNEW(Data(x,tmp.ptr()->size()-size+consumed))));
                consumed += size-consumed ;
            }
            // check wheater to iniatiate a new input ready
        }
        if (reader())
        {
            
            if (datas_.count())
                startTimer_() ;
            else
            {
                stopTimer_() ;
                tio_.ptr()->registerInput(this) ; 
            }   
        }
        return consumed;
    }
}

void TransparentBReadIO::putBack(const char* it,int size) 
{
   DEBUGNL ("TransparentBReadIO::putBack(): "<<size<<" bytes") ;
   hgassert(size && it,"TransparentBReadIO::putBack() size or nil ptr") ;

   if (!datas_.count() && reader()) {
      // my tio_ is active. I will put back something, which will make
      // me active myself. deactivate the tio_. (jfasch for
      // efficiency, it would have no effect on correctness if it
      // weren't.)
      tio_.ptr()->registerInput (nil) ;
   }

   char* tmp = HGNEW(char [size]);
   ::memcpy(tmp,it,size);
   datas_.unshift(DataPtr(HGNEW(Data(tmp,size))));  // put it back

   if (reader())
      // "make the put back data active"
      startTimer_() ;
}

void TransparentBReadIO :: egoist (bool b) {
   tio_.ptr()->egoist (b) ;
}

void TransparentBReadIO::inputReady (const TransparentIO* )   
{
    hgassert(reader(),"TransparentBReadIO::inputReady() got no reader") ;
    get_reader_()->inputReady(this);
}


void TransparentBReadIO::timerExpired (long, long)
{
    // means we have data so call inputReady
    hgassert(reader(),"TransparentBReadIO::timerExpired() got no reader") ;
    hgassert(datas_.count(),"TransparentBReadIO::timerExpired() no data available") ;
    // this is a little bit tricky
    // inputReady should be called again even if nothing is read,
    // so we initiate a timer, which is occasionally removed by read()

    // this was a bug: the timer is not running anymore, but of course
    // nobody resets the flag. hence startTimer_() did not restart the
    // timer. HAVE TO CLEAR THE FLAG BY MYSELF.
    timerisrunning_ = false ; // SHIT!!

    // now it should work
    startTimer_() ;
    
    get_reader_()->inputReady(this);
}

// ------------------------ output stuuf

void TransparentBReadIO::registerOutput(TransparentIOHandler* it)
{
    hgassert(tio_.ok(),"TransparentBReadIO::registerOutput() no tio set") ; 
    if (it == 0)  // unlink
    {
        tio_.ptr()->registerOutput(0) ;
    }
    else
    {
        tio_.ptr()->registerOutput(this) ;
    }
    set_writer_(it) ;
}

int TransparentBReadIO::write(const char* it, int size)
{
   DEBUGNL ("TransparentBReadIO::write("<<size<<" bytes)") ;
   hgassert(tio_.ok(),"TransparentBReadIO::write() no tio set") ; 
   return tio_.ptr()->write(it,size) ;
}
    
void TransparentBReadIO::outputReady(const TransparentIO*)
{
    hgassert(writer(),"TransparentBReadIO::outputReady() got no writer") ;
    get_writer_()->outputReady(this);
}









