// This may look like C code, but it is really -*- C++ -*-

// **********************************************************
// File rvwman.C
// ----------------------------------------------------------
// Created: J. Faschingbauer
// **********************************************************
#include "rvwstuff.h"

#include <hyperg/hyperg/assert.h>


#include <InterViews/session.h>
#include <Dispatch/rpcstream.h>
#include <Dispatch/rpchdr.h>



#include <iostream.h>



#define VERBOSE
#include <hyperg/hyperg/verbose.h>


const boolean RemoteViewerManager :: binary = false ;


// **********************************************************
// class RemoteViewerManager
// **********************************************************
RemoteViewerManager :: RemoteViewerManager (int fd) {
   DEBUGNL ("RemoteViewerManager::RemoteViewerManager()") ;
   _writer = new RemoteWriter (fd) ;
   _reader = new RemoteReader (&_writer->server(), this) ;
}

RemoteViewerManager :: ~RemoteViewerManager () {
   delete _reader ;
   delete _writer ;
}

void RemoteViewerManager :: followLink (const RString& link, HgViewer*) {
   _writer->sendFollowLink (link) ;
}
void RemoteViewerManager :: viewerError (HgViewer* viewer) {
   _writer->sendError (viewer->error()) ;
}
void RemoteViewerManager :: viewerTerminated (const RString& obj, HgViewer*) {
   _writer->sendTerminated (obj) ;
}
void RemoteViewerManager :: viewer (HgViewer* viewer) {
   _viewer = viewer ;
   _writer->sendReady (_viewer->port(), _viewer->options()) ;
   DEBUGNL ("RemoteViewerManager::viewer(): return ") ;
}

void RemoteViewerManager :: defineSourceAnchor (const RString& anch, HgViewer*) {
   _writer->sendDefineSourceAnchor (anch) ;
}
void RemoteViewerManager :: defineDestAnchor (const RString& anch, HgViewer*) {
   _writer->sendDefineDestAnchor (anch) ;
}
void RemoteViewerManager :: deleteLink (const RString& link, HgViewer*) {
   _writer->sendDeleteLink (link) ;
}
void RemoteViewerManager :: showReferences (const RString& object, HgViewer*) {
   _writer->sendShowReferences (object) ;
}
void RemoteViewerManager :: showAnnotations (const RString& object, HgViewer*) {
   _writer->sendShowAnnotations (object) ;
}
void RemoteViewerManager :: showParents (const RString& object, HgViewer*) {
   _writer->sendShowParents (object) ;
}
void RemoteViewerManager :: showAttributes (const RString& object, HgViewer*) {
   _writer->sendShowAttributes (object) ;
}
void RemoteViewerManager :: back (HgViewer*) {
   _writer->sendBack() ;
}
void RemoteViewerManager :: forward (HgViewer*) {
   _writer->sendForward() ;
}
void RemoteViewerManager :: history (HgViewer*) {
   _writer->sendHistory() ;
}
void RemoteViewerManager :: hold (const RString& object, HgViewer*) {
   _writer->sendHold (object) ;
}
void RemoteViewerManager :: edit (const RString& object, HgViewer*) {
   _writer->sendEdit (object) ;
}
void RemoteViewerManager :: upload (const RString& object, const RString& anchors, const RString& host, int port, HgViewer*, int refno) {
   _writer->sendUpload (object, anchors, host, port, refno) ;
}
void RemoteViewerManager :: cancelEdit (const RString& object, HgViewer*) {
   _writer->sendCancelEdit (object) ;
}
void RemoteViewerManager :: modifyAttribute (const RString& object) {
   _writer->sendModifyAttribute (object) ;
}
void RemoteViewerManager :: reloadDocument (const RString& object) {
   _writer->sendReloadDocument (object) ;
}





// **********************************************************
// class RemoteWriter
// **********************************************************
RemoteWriter :: RemoteWriter (int fd)
 : RpcWriter (fd, true, RemoteViewerManager::binary) {
   server().nonblocking (true) ;
   DEBUGNL ("RemoteWriter: nonblocking: "<<server().rdbuf()->nonblocking()) ;
}


// send rpc requests ------------------------------------------

void RemoteWriter :: sendReady (int port, const RString& options) {
   DEBUGNL ("RemoteWriter::sendReady()") ;
   server() << RpcHdr (nil, READY) ; 
   server() << port ;
   server() << options.string() ;
   server().flush() ;
   DEBUGNL ("RemoteWriter::sendReady(): return") ;
}

void RemoteWriter :: sendFollowLink (const RString& link) {
   DEBUG ("RemoteWriter::sendFollowLink():") ;   DEBUGNL (link) ;   
   server() << RpcHdr (nil, FOLLOWLINK) ; 
   server() << link.string() ;
   server().flush() ;
}
void RemoteWriter :: sendError (HgViewer::VwError err) {
   DEBUG ("RemoteWriter::sendError():") ;   DEBUGNL ((long)err) ;   
   server() << RpcHdr (nil, ERROR) ;
   server() << (int) err ;
   server().flush() ;
}
void RemoteWriter :: sendTerminated (const RString& obj) {
   DEBUGNL ("RemoteWriter::sendTerminated()") ;
   server() << RpcHdr (nil, TERMINATED) ;
   server() << obj.string() ;
   server().flush() ;
}
void RemoteWriter :: sendAddInfo (const RString& info) {
   DEBUGNL ("RemoteWriter::sendAddInfo()") ;
   server() << RpcHdr (nil, ADDINFO) ;
   server() << info.string() ;
   server().flush() ;
}

void RemoteWriter :: sendDefineSourceAnchor (const RString& anch) {
   DEBUGNL ("RemoteWriter::sendDefineSourceAnchor()") ;
   server() << RpcHdr (nil, DEFSRCANCH) ;
   server() << anch.string() ;
   server().flush() ;
}
void RemoteWriter :: sendDefineDestAnchor (const RString& anch) {
   DEBUGNL ("RemoteWriter::sendDefineDestAnchor()") ;
   server() << RpcHdr (nil, DEFDESTANCH) ;
   server() << anch.string() ;
   server().flush() ;
}

void RemoteWriter :: sendDeleteLink (const RString& link) {
   DEBUGNL ("RemoteWriter::sendDeleteLink()") ;
   server() << RpcHdr (nil, DELLINK) ;
   server() << link.string() ;
   server().flush() ;
}
void RemoteWriter :: sendShowReferences (const RString& object) {
   DEBUGNL ("RemoteWriter::sendShowReferences()") ;
   server() << RpcHdr (nil, SHOWREFERENCES) ;
   server() << object.string() ;
   server().flush() ;
}
void RemoteWriter :: sendShowAnnotations (const RString& object) {
   DEBUGNL ("RemoteWriter::sendShowAnnotations()") ;
   server() << RpcHdr (nil, SHOWANNOTATIONS) ;
   server() << object.string() ;
   server().flush() ;
}
void RemoteWriter :: sendShowParents (const RString& object) {
   DEBUGNL ("RemoteWriter::sendShowParents()") ;
   server() << RpcHdr (nil, SHOWPARENTS) ;
   server() << object.string() ;
   server().flush() ;
}
void RemoteWriter :: sendShowAttributes (const RString& object) {
   DEBUGNL ("RemoteWriter::sendShowAttributes()") ;
   server() << RpcHdr (nil, SHOWATTRIBUTES) ;
   server() << object.string() ;
   server().flush() ;
}
void RemoteWriter :: sendBack() {
   DEBUGNL ("RemoteWriter::sendBack()") ;
   server() << RpcHdr (nil, BACK) ;
   server().flush() ;
}
void RemoteWriter :: sendForward() {
   DEBUGNL ("RemoteWriter::sendForward()") ;
   server() << RpcHdr (nil, FORWARD) ;
   server().flush() ;
}
void RemoteWriter :: sendHistory() {
   DEBUGNL ("RemoteWriter::sendHistory()") ;
   server() << RpcHdr (nil, HISTORY) ;
   server().flush() ;
}
void RemoteWriter :: sendHold (const RString& object) {
   DEBUGNL ("RemoteWriter::sendHold()") ;
   server() << RpcHdr (nil, HOLD) ;
   server() << object.string() ;
   server().flush() ;
}
void RemoteWriter :: sendEdit (const RString& object) {
   DEBUGNL ("RemoteWriter::sendEdit()") ;
   server() << RpcHdr (nil, EDIT) ;
   server() << object.string() ;
   server().flush() ;
}
void RemoteWriter :: sendUpload (const RString& object, const RString& anchors, const RString& host, int port, int refno) {
   DEBUGNL ("RemoteWriter::sendUpload()") ;
   server() << RpcHdr (nil, UPLOAD) ;
   server() << object.string() ;
   server() << anchors.string() ;
   server() << host.string() ;
   server() << port ;
   server() << refno ;
   server().flush() ;
}
void RemoteWriter :: sendCancelEdit (const RString& object) {
   DEBUGNL ("RemoteWriter::sendCancelEdit()") ;
   server() << RpcHdr (nil, CANCELEDIT) ;
   server() << object.string() ;
   server().flush() ;
}
void RemoteWriter :: sendModifyAttribute (const RString& object) {
   DEBUGNL ("RemoteWriter::sendModifyAttribute()") ;
   server() << RpcHdr (nil, MODIFYATTRIBUTE) ;
   server() << object.string() ;
   server().flush() ;
}
void RemoteWriter :: sendReloadDocument (const RString& object) {
   DEBUGNL ("RemoteWriter::sendReloadDocument()") ;
   server() << RpcHdr (nil, RELOADDOCUMENT) ;
   server() << object.string() ;
   server().flush() ;
}

void RemoteWriter :: sendString (const RString& s) {
   DEBUGNL ("RemoteWriter::sendString()") ;
   server() << RpcHdr (nil, STRING) ;
   server() << s.string() ;
   server().flush() ;
}





// **********************************************************
// class RemoteReader
// **********************************************************
RemoteReader :: RemoteReader (rpcstream* server, RemoteViewerManager* manager) 
: RpcReader (server, NFCNS) ,
  manager_ (manager) {
   DEBUG ("RemoteReader: nonblocking:") ;   DEBUGNL (client().rdbuf()->nonblocking()) ;

   _function[READY] = &RemoteReader::receive_READY ;
   _function[LOAD] = &RemoteReader::receive_LOAD ;
   _function[LOAD1] = &RemoteReader::receive_LOAD1 ;
   _function[BROWSE] = &RemoteReader::receive_BROWSE ;
   _function[TERMINATE] = &RemoteReader::receive_TERMINATE ;

   _function[CANCELREQUEST] = &RemoteReader::receive_CANCELREQUEST ;

   _function[HOLDDOCUMENT] = &RemoteReader::receive_HOLDDOCUMENT ;
   _function[ICONIFY] = &RemoteReader::receive_ICONIFY ;
   _function[DEICONIFY] = &RemoteReader::receive_DEICONIFY ;
   _function[MOVETO] = &RemoteReader::receive_MOVETO ;
   _function[RESIZE] = &RemoteReader::receive_RESIZE ;
   _function[MAP] = &RemoteReader::receive_MAP ;
   _function[UNMAP] = &RemoteReader::receive_UNMAP ;
   _function[RAISE] = &RemoteReader::receive_RAISE ;
   _function[LOWER] = &RemoteReader::receive_LOWER ;

   _function[SETLANG] = &RemoteReader::receive_SETLANG ;

   _function[SAVERESOURCES] = &RemoteReader::receive_SAVERESOURCES ;
   _function[DOEDIT] = &RemoteReader::receive_DOEDIT ;
   _function[NEWDOC] = &RemoteReader::receive_NEWDOC ;
   _function[GETPOS] = &RemoteReader::receive_GETPOS ;
}



// // for testing purposes:
// int RemoteReader::inputReady(int fd) {
//    DEBUGNL ("RemoteReader::inputReady") ;
//    RpcHdr hdr;
// 
//    client() >> hdr;
//    
//    if (client().good() && !client().incomplete_request()) {
//       RpcReader* reader = map(hdr.reader());
//       
//       if (!execute(reader, hdr)) {
// 	 client().ignore(hdr.ndata());
//       }
//    }
// 
//    if (client().eof() || client().fail()) {
//       if (client().fail())
// 	 DEBUGNL ("RemoteReader::inputReady:  fail") ;
//       if (client().eof())
// 
// 	 DEBUGNL ("RemoteReader::inputReady:  eof") ;
//       connectionClosed(fd);
//       return -1;		// don't ever call me again (i.e., detach me)
//    } else if (client().incomplete_request()) {
//       DEBUGNL ("RemoteReader::inputReady: incomplete_request") ;
//       return 0;		// call me only when more input arrives
//    } else {
//       return 1;		// call me again as soon as possible
//    }
// }

void RemoteReader :: connectionClosed (int) {
   DEBUGNL ("RemoteReader::connectionClosed()") ;
   manager_->viewer()->terminate() ;
   Session::instance()->quit() ;
}


// read rpc requests ------------------------------------------------------

void RemoteReader :: receive_READY (RpcReader* reader, RpcHdr&, rpcstream&) {
   DEBUGNL ("RemoteReader::receive_READY") ;
   ((RemoteReader*)reader)->manager()->writer()->
      sendReady (((RemoteReader*)reader)->manager()->viewer()->port(),
                 ((RemoteReader*)reader)->manager()->viewer()->options());
}

void RemoteReader :: receive_LOAD (RpcReader* reader, RpcHdr& header, rpcstream& client) {
   DEBUGNL ("RemoteReader::receive_LOAD: ") ;
   char* doc     = new char [header.ndata()+1] ;    doc[0] = '\0' ;
   char* anchors = new char [header.ndata()+1] ;    anchors[0] = '\0' ;
   client >> doc ;
   client >> anchors ;
   DEBUGNL ("Document: " << doc) ;
   DEBUGNL ("Anchors:  " << anchors) ;

   ((RemoteReader*)reader)->manager()->viewer()->load (doc, anchors) ;

   delete doc ;
   delete anchors ;
}
void RemoteReader :: receive_LOAD1 (RpcReader* reader, RpcHdr& header, rpcstream& client) {
   DEBUGNL ("RemoteReader::receive_LOAD1: ") ;
   char* doc     = new char [header.ndata()+1] ;    doc[0] = '\0' ;
   char* anchors = new char [header.ndata()+1] ;    anchors[0] = '\0' ;
   client >> doc ;
   client >> anchors ;
   DEBUGNL ("Document: " << doc) ;
   DEBUGNL ("Anchors:  " << anchors) ;

   char add_info[64] ;     add_info[0] = '\0' ;
   ((RemoteReader*)reader)->manager()->viewer()->load (doc, anchors, add_info) ;


   char* jfaschinfo = "hahahaha, war das ein Scherz !!!" ;

//    ((RemoteReader*)reader)->manager()->writer()->sendAddInfo (add_info) ;
   ((RemoteReader*)reader)->manager()->writer()->sendAddInfo (jfaschinfo) ;
   

   delete doc ;
   delete anchors ;
}
void RemoteReader :: receive_BROWSE (RpcReader* reader, RpcHdr& header, rpcstream& client) {
   DEBUG ("RemoteReader::receive_BROWSE: ") ;
   char* dest ;

   if (header.ndata()) {
      dest = new char [header.ndata()+1] ;
      client >> dest ;
   }
   else 
      dest = "" ;

   ((RemoteReader*)reader)->manager()->viewer()->browse (dest) ;

   delete dest ;
}
void RemoteReader :: receive_TERMINATE (RpcReader* reader, RpcHdr&, rpcstream&) {
   DEBUGNL ("RemoteReader::receive_TERMINATE") ;

   ((RemoteReader*)reader)->manager()->viewer()->terminate() ;
   Session::instance()->quit() ;
}

void RemoteReader :: receive_CANCELREQUEST (RpcReader* reader, RpcHdr& hdr, rpcstream& client) {
   DEBUGNL ("RemoteReader::receive_CANCELREQUEST()") ;
   char* s = new char [hdr.ndata() + 1] ;
   client >> s ;
   ((RemoteReader*)reader)->manager()->viewer()->cancelRequest (s) ;
   delete s ;
}

void RemoteReader :: receive_HOLDDOCUMENT (RpcReader* reader, RpcHdr& hdr, rpcstream& client) {
   DEBUGNL ("RemoteReader::receive_HOLDDOCUMENT()") ;
   char* s = new char [hdr.ndata() + 1] ;
   client >> s ;
   ((RemoteReader*)reader)->manager()->viewer()->holdDocument (s) ;
   delete s ;
}
void RemoteReader :: receive_ICONIFY (RpcReader* reader, RpcHdr&, rpcstream&) {
   DEBUGNL ("RemoteReader::receive_ICONIFY()") ;
   ((RemoteReader*)reader)->manager()->viewer()->iconify() ;
}
void RemoteReader :: receive_DEICONIFY (RpcReader* reader, RpcHdr&, rpcstream&) {
   DEBUGNL ("RemoteReader::receive_deiconify()") ;
   ((RemoteReader*)reader)->manager()->viewer()->deiconify() ;
}
void RemoteReader :: receive_MOVETO (RpcReader* reader, RpcHdr&, rpcstream& client) {
   DEBUGNL ("RemoteReader::receive_moveto()") ;
   float x ;   client >> x ;
   float y ;   client >> y ;
   ((RemoteReader*)reader)->manager()->viewer()->moveto (x,y) ;
}
void RemoteReader :: receive_RESIZE (RpcReader* reader, RpcHdr&, rpcstream& client) {
   DEBUGNL ("RemoteReader::receive_RESIZE()") ;
   float x ;   client >> x ;
   float y ;   client >> y ;
   ((RemoteReader*)reader)->manager()->viewer()->resize (x,y) ;
}
void RemoteReader :: receive_MAP (RpcReader* reader, RpcHdr&, rpcstream&) {
   DEBUGNL ("RemoteReader::receive_MAP()") ;
   ((RemoteReader*)reader)->manager()->viewer()->map() ;
}
void RemoteReader :: receive_UNMAP (RpcReader* reader, RpcHdr&, rpcstream&) {
   DEBUGNL ("RemoteReader::receive_UNMAP()") ;
   ((RemoteReader*)reader)->manager()->viewer()->unmap() ;
}
void RemoteReader :: receive_RAISE (RpcReader* reader, RpcHdr&, rpcstream&) {
   DEBUGNL ("RemoteReader::receive_RAISE()") ;
   ((RemoteReader*)reader)->manager()->viewer()->raise() ;
}
void RemoteReader :: receive_LOWER (RpcReader* reader, RpcHdr&, rpcstream&) {
   DEBUGNL ("RemoteReader::receive_LOWER()") ;
   ((RemoteReader*)reader)->manager()->viewer()->lower() ;
}

void RemoteReader :: receive_SETLANG (RpcReader* reader, RpcHdr&, rpcstream& client) {
   DEBUGNL ("RemoteReader::receive_SETLANG()") ;
   int l ;   client >> l ;
   hgassert (l>=HgLanguage::English&&l<HgLanguage::NumLanguages,
             "RemoteReader::receive_SETLANG(): invalid language") ;
   ((RemoteReader*)reader)->manager()->viewer()->setLanguage (HgLanguage::Language(l)) ;
}
void RemoteReader :: receive_SAVERESOURCES (RpcReader* reader, RpcHdr&, rpcstream&) {
   DEBUGNL ("RemoteReader::receive_SAVERSOURCES()") ;
   ((RemoteReader*)reader)->manager()->viewer()->saveResources() ;
}
void RemoteReader :: receive_DOEDIT (RpcReader* reader, RpcHdr& hdr, rpcstream& client) {
   DEBUGNL ("RemoteReader::receive_DOEDIT()") ;
   RString object, anchors ;
   char* tmp = new char [hdr.ndata()+1] ;
   client >> tmp ;  object = tmp ;
   client >> tmp ;  anchors = tmp ;
   delete tmp ;
   ((RemoteReader*)reader)->manager()->viewer()->doEdit (object, anchors) ;   
}
void RemoteReader :: receive_NEWDOC (RpcReader* reader, RpcHdr& hdr, rpcstream& client) {
   DEBUGNL ("RemoteReader::receive_NEWDOC()") ;
   int refno ;
   client >> refno ;
   char* tmp = new char [hdr.ndata()] ;
   client >> tmp ;
   RString info (tmp) ;
   delete[] tmp ;
   ((RemoteReader*)reader)->manager()->viewer()->newDoc (refno, info) ;
}
void RemoteReader :: receive_GETPOS (RpcReader* reader, RpcHdr&, rpcstream&) {
   DEBUGNL ("RemoteReader::receive_GETPOS()") ;
   RString pos ;
   ((RemoteReader*)reader)->manager()->viewer()->getPos (pos) ;
   ((RemoteReader*)reader)->manager()->writer()->sendString (pos) ;
}

