// 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:        tsockio.C
// 
// Purpose:     
// 
// Created:     11 Mar 96   Joerg Faschingbauer
// 
// Modified:    
// 
// Description: 
// 
// $Id: tsockio.C,v 1.11 1997/03/04 13:32:39 jfasch Exp $
// 
// $Log: tsockio.C,v $
// Revision 1.11  1997/03/04 13:32:39  jfasch
// more output in one assertion
//
// Revision 1.10  1997/02/21 16:23:41  jfasch
// egoist() implemented
//
// Revision 1.9  1997/02/12 23:13:11  jfasch
// moved from HgDcCommon
//
// Revision 1.8  1997/02/05 13:06:09  jfasch
// bug fix in ctor: mark socket as blocking because no reader is yet
// registered.
//
// Revision 1.7  1996/12/17 13:22:04  jfasch
// - DEBUGNL
// - VERBOSE graffl
//
// Revision 1.6  1996/10/03 12:02:50  jfasch
// verbose.h and assert.h moved
//
// Revision 1.5  1996/08/05 16:01:48  jfasch
// possible to use local Dispatcher
//
// Revision 1.4  1996/07/24 05:13:28  jfasch
// corrected some text in an assertion
//
// Revision 1.3  1996/05/23 14:47:05  jfasch
// *** empty log message ***
//
// Revision 1.2  1996/03/28 09:51:54  jfasch
// decoupling things from Dispatcher
//
// Revision 1.1  1996/03/22 16:23:11  jfasch
// Initial revision
//
// 
// </file> 
#include "tsockio.h"

#include "dispatcher.h"
#include "fdmask.h"

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

// --------------------------------------------------------------------
const char* TransparentSocketIO::version4 = "$Id: tsockio.C,v 1.11 1997/03/04 13:32:39 jfasch Exp $" ;

TransparentSocketIO :: TransparentSocketIO (const SocketPtr& s, Dispatcher* d) 
: socket_(s),
  dispatcher_(d?d:&Dispatcher::instance()) {
     hgassert (socket_.ok()&&socket_.ptr()->ok(), "TransparentSocketIO::TransparentSocketIO(): "
               "socket not allocated or not open") ;
     // was a bug fix: if the socket is marked nonblocking, it will
     // remain so. this will result in an error if a read() is done
     // without having registered first (the errno being EAGAIN).
     socket_.ptr()->blocking (true) ;
}

TransparentSocketIO :: ~TransparentSocketIO() {
   DEBUGNL ("TransparentSocketIO::~TransparentSocketIO()") ;
   hgassert (!reader(), "TransparentSocketIO::~TransparentSocketIO(): "
             "still someone registered for read events") ;
   hgassert (!writer(), "TransparentSocketIO::~TransparentSocketIO(): "
             "still someone registered for write events") ;
}

void TransparentSocketIO :: registerInput (TransparentIOHandler* h) {
   DEBUGNL ("TransparentSocketIO::registerInput("<<h<<')') ;
   if (! h) {
      if (reader()) {
         set_reader_(nil) ;
         if (! writer())
            // have to reset back to blocking mode when no-one wants to
            // be called back anymore
            socket_.ptr()->blocking (true) ;
         dispatcher_->unlink (socket_.ptr()->fd(), Dispatcher::ReadMask) ;
      }
      // else ignore 
   }
   else {
      hgassert (!reader(), "TransparentSocketIO::registerInput(non-nil): already registered") ;
      set_reader_(h) ;
      socket_.ptr()->blocking (false) ;
      dispatcher_->link (socket_.ptr()->fd(), Dispatcher::ReadMask, this) ;
   }
}

void TransparentSocketIO :: registerOutput (TransparentIOHandler* h) {
   DEBUGNL ("TransparentSocketIO::registerOutput("<<h<<')') ;
   if (! h) {
      if (writer()) {
         set_writer_(nil) ;
         if (! reader()) 
            // have to reset back to blocking mode when no-one wants to
            // be called back anymore
            socket_.ptr()->blocking (true) ;
         dispatcher_->unlink (socket_.ptr()->fd(), Dispatcher::WriteMask) ;
      }
      // else ignore
   }
   else {
      hgassert (!writer(), "TransparentSocketIO::registerOutput(non-nil): already registered") ;
      set_writer_(h) ;
      socket_.ptr()->blocking (false) ;
      dispatcher_->link (socket_.ptr()->fd(), Dispatcher::WriteMask, this) ;
   }
}

int TransparentSocketIO :: read (char* buf, int len) {
   return socket_.ptr()->read (buf, len) ;
}

int TransparentSocketIO :: write (const char* buf, int len) {
   DEBUGNL ("TransparentSocketIO::write("<<len<<" bytes)") ;
   return socket_.ptr()->write (buf, len) ;
}

int TransparentSocketIO :: inputReady (int fd) {
   hgassert (socket_.ptr()->fd()==fd, "TransparentSocketIO::inputReady(): not my fd: "<<fd) ;
   hgassert (reader(), "TransparentSocketIO::inputReady(): got no reader") ;
   get_reader_()->inputReady (this) ;
   return 0 ;
}

int TransparentSocketIO :: outputReady (int fd) {
   hgassert (socket_.ptr()->fd()==fd, "TransparentSocketIO::outputReady(): not my fd") ;
   hgassert (writer(), "TransparentSocketIO::outputReady(): got no writer") ;
   get_writer_()->outputReady (this) ;
   return 0 ;
}

void TransparentSocketIO :: egoist (bool b) {
   hgassert (socket_.ok(), "TransparentSocketIO::egoist(): nil socket") ;
   if (b) {
      FdMask read,write,exception;
      read.setBit (socket_.ptr()->fd()) ;
      write.setBit (socket_.ptr()->fd()) ;
      Dispatcher::instance().setActive (read,write,exception) ;
   }
   else {
      Dispatcher::instance().resetActive() ;
   }
}
