// This may look like C code, but it is really -*- C++ -*-
// 
// <copyright> 
//  
//  Copyright (c) 1996
//  Institute for Information Processing and Computer Supported New Media (IICM), 
//  Graz University of Technology, Austria. 
//  
// </copyright> 
// 
// 
// <file> 
// 
// Name:        tioinetsrc_a.C
// 
// Purpose:     
// 
// Created:     18 Jun 96   Joerg Faschingbauer
// 
// Modified:    
// 
// Description: 
// 
// $Id: tioinetsrc_a.C,v 1.10 1997/02/19 16:15:01 jfasch Exp $
// 
// $Log: tioinetsrc_a.C,v $
// Revision 1.10  1997/02/19 16:15:01  jfasch
// 'for' scoping
//
// Revision 1.9  1997/02/13 13:12:40  gorasche
// minor changes for Win32
//
// Revision 1.8  1997/02/12 23:13:11  jfasch
// moved from HgDcCommon
//
// Revision 1.7  1996/12/18 15:42:56  jfasch
// added the more specific
//    virtual void cancel (const TIOSourceActiveUser_INET*) ;
//
// Revision 1.6  1996/12/17 13:19:11  jfasch
// a different make() function to be INET specific (if one wants to).
//
// Revision 1.5  1996/12/12 15:02:19  jfasch
// added the more specific
// TIOSourceActive::Make TIOSourceActive_INET::make (TransparentINETSocketIOPtr&,
//                                                   TIOSourceActiveUser*,
//                                                   TIOSourceActiveUser_INET*) ;
//
// Revision 1.4  1996/10/03 12:02:50  jfasch
// verbose.h and assert.h moved
//
// Revision 1.3  1996/08/02 13:45:39  jfasch
// removed compiler warning
//
// Revision 1.2  1996/07/22 08:18:19  jfasch
// *** empty log message ***
//
// Revision 1.1  1996/07/08 13:16:36  jfasch
// Initial revision
//
// 
// </file> 
#include "tioinetsrc_a.h"

#include "tifs.h"
#include "tsockio.h"

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

// --------------------------------------------------------------------
class TIO_INET_Pair {
public:
   TIO_INET_Pair() : user_(nil) {}
   TIO_INET_Pair (const TIOINETRequestPtr&, TIOSourceActiveUser*, TIOSourceActiveUser_INET*) ;
   const TIOINETRequestPtr& request() const { return request_; }
   TIOSourceActiveUser* user() const { return user_; }
   TIOSourceActiveUser_INET* inetuser() const { return inetuser_; }
   // these are only dummies to be able to instantiate a template/macro over this.
   bool operator < (const TIO_INET_Pair&) const { return false; }
   bool operator == (const TIO_INET_Pair&) const { return false; }
   bool operator != (const TIO_INET_Pair& p) const { return !operator==(p); }
private:
   TIOINETRequestPtr request_ ;
   TIOSourceActiveUser* user_ ;
   TIOSourceActiveUser_INET* inetuser_ ;
} ;
inline TIO_INET_Pair :: TIO_INET_Pair (const TIOINETRequestPtr& req,
                                       TIOSourceActiveUser* u, 
                                       TIOSourceActiveUser_INET* ui)
: request_(req), 
  user_(u),
  inetuser_(ui) {}

Fieldsdeclare (TIO_INET_Lookup, TIO_INET_Pair);
Fieldsimplement (TIO_INET_Lookup, TIO_INET_Pair);

// --------------------------------------------------------------------
const char* TIOSourceActive_INET :: version2 = "TIOSourceActive_INET: $Id: tioinetsrc_a.C,v 1.10 1997/02/19 16:15:01 jfasch Exp $" ;

TIOSourceActive_INET :: TIOSourceActive_INET (const INETAddress& a, long t)
: addr_(a), 
  timeout_(t),
  requests_(HGNEW (TIO_INET_Lookup)) {
     hgassert (addr_, "TIOSourceActive_INET::TIOSourceActive_INET(): invalid address") ;
}

TIOSourceActive_INET :: ~TIOSourceActive_INET() {
   int i ;
   for (i=0 ; i<requests_->count() ; i++) 
      requests_->operator[](i).user()->tioSrcAError (this) ;
   // cancel all pending requests
   for (i=0 ; i<requests_->count() ; i++) {
      // have to copy it out of the list because the Doze compiler
      // shit does not understand a reference (what are these guys
      // doing all the time? design hopping buttons???)
      TIOINETRequestPtr r = requests_->operator[](i).request() ;
      hgassert (r.ok(), "TIOSourceActive_INET::~TIOSourceActive_INET(): "
                "nil request in my list") ;
      r.ptr()->cancel (this) ;
   }
   HGDELETE (requests_) ;
}

TIOSourceActive::Make TIOSourceActive_INET :: make (TransparentIOPtr& io, 
                                                    TIOSourceActiveUser* u) {
   TIOINETAttributes attr ;
   return make_(io, attr, u, nil) ;
}

TIOSourceActive::Make TIOSourceActive_INET :: make (TransparentIOPtr& io, 
                                                    TIOINETAttributes& attr,
                                                    TIOSourceActiveUser* u,
                                                    TIOSourceActiveUser_INET* ui) {
   return make_(io, attr, u, ui) ;
}

void TIOSourceActive_INET :: cancel (const TIOSourceActiveUser* u) {
   cancel_(u, nil) ;
}

void TIOSourceActive_INET :: cancel (const TIOSourceActiveUser_INET* u) {
   cancel_(nil, u) ;
}

void TIOSourceActive_INET :: tioInetResponse (const TIOINETResponsePtr& res) {
   DEBUGNL ("TIOSourceActive_INET::tioInetResponse()") ;
   hgassert (res.ok(), "TIOSourceActive_INET::tioInetResponse(): nil response") ;
   hgassert (res.ptr()->request(), "TIOSourceActive_INET::tioInetResponse(): "
             "issuer-request not registered in response") ;

   TIO_INET_Pair p ;
   for (int i=0 ; i<requests_->count() ; i++) {
      p = requests_->operator[](i) ;
      if (p.request().ptr() == res.ptr()->request()) {
         requests_->remove (i) ;
         break ;
      }
      else 
         p = TIO_INET_Pair() ;
   }
   hgassert (p.request(), "TIOSourceActive_INET::tioInetResponse(): "
             "corresponding request not found") ;

   TIOSourceActiveUser* u = p.user() ;
   TIOSourceActiveUser_INET* ui = p.inetuser() ;
   hgassert (u||ui, "TIOSourceActive_INET::tioInetResponse(): "
             "no user seems to have issued that request") ;

   if (res.ptr()->error()) {
      DEBUGNL ("TIOSourceActive_INET::tioInetResponse(): error "<<(int)res.ptr()->error()) ;
      if (u) u->tioSrcAError (this) ;
      if (ui) ui->tioSrcAINETError (this) ;
   }
   else {
      hgassert (res.ptr()->io(), 
                "TIOSourceActive_INET::tioInetResponse(): no error and nil io") ;
      if (u) u->tioSrcAReady (this, res.ptr()->io()) ;
      if (ui) ui->tioSrcAINETReady (this, res.ptr()->io(), res.ptr()->attributes()) ;
   }
}

TIOSourceActive::Make TIOSourceActive_INET :: make_(TransparentIOPtr& io, 
                                                    TIOINETAttributes& attr, 
                                                    TIOSourceActiveUser* u, 
                                                    TIOSourceActiveUser_INET* ui) {
   hgassert (u||ui, "TIOSourceActive_INET::make_(): at least 1 callback has to be passed") ;

   TIOINETRequestPtr req (HGNEW (TIOINETRequest (addr_, this))) ;
   TIOINETResponsePtr res = TIOINETFactories::instance().connect (req) ;
   
   if (res.ok()) {
      if (res.ptr()->error()) {
         DEBUGNL ("TIOSourceActive_INET::make_(): immediate error") ;
         return TIOSourceActive::TIOERROR ;
      }
      else {
         DEBUGNL ("TIOSourceActive_INET::make_(): immediate response") ;
         hgassert (res.ptr()->io(), "TIOSourceActive_INET::make_(): "
                   "immediate response and io not set") ;
         io = res.ptr()->io() ;
         attr = res.ptr()->attributes() ;
         return TIOSourceActive::TIOREADY ;
      }
   }
   else {
      // put back the request (along with my user(s)) for later lookup
      // (when the response comes along).
      TIO_INET_Pair p (req, u, ui) ;
      requests_->append (p) ;
      return TIOSourceActive::TIOWAIT ;
   }
}

void TIOSourceActive_INET :: cancel_(const TIOSourceActiveUser* u,
                                     const TIOSourceActiveUser_INET* ui) {
   TIO_INET_Pair p ;
   for (int i=0 ; i<requests_->count() ; i++) {
      // have to copy for some NT reason
      TIO_INET_Pair p = requests_->operator[](i) ;
      hgassert (p.request().ok(), 
                "TIOSourceActive_INET::cancel_(): found nil request in my list") ;
      if ((p.user() && p.user() == u)  ||  (p.inetuser() && p.inetuser() == ui)) {
         p.request().ptr()->cancel (this) ;
         requests_->remove (i) ;
         break ;
      }
   }
   hgassert (false, "TIOSourceActive_INET::cancel_(): no such user found in my list") ;
}
