/*
_____       _    _    Corso   Italia,  178
(_|__   .  (_   |_|_  56125           Pisa
(_|_) |)|(()_)()| |   tel.  +39  050 46380
  |   |               picosoft@picosoft.it

 picoiiop - network support for picoSQL

 Copyright (C) Picosoft s.r.l. 1994-2002

 This library is free software; you can redistribute it and/or
 modify it under the terms of the GNU Lesser General Public
 License as published by the Free Software Foundation; either
 version 2.1 of the License, or (at your option) any later version.

 This library is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 Lesser General Public License for more details.

 You should have received a copy of the GNU Lesser General Public
 License along with this library; if not, write to the Free Software
 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/
# ifdef WIN32
# include <io.h>
# else
# include <unistd.h>
# endif
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <fcntl.h>
#include "invoke.h"
#include "message.h"
#include "log.h"

static char *rcsid = "$Id: invoke.c,v 1.1 1999/06/03 11:42:53 picoSoft Exp $";
static char *rcsidh = invoke_h;

Invoke *
Invoke_new()
{
   Invoke *this = (Invoke *)malloc (sizeof(Invoke));
   if (this) {
      this->methods = 0;
      this->obj = 0;
      this->conn = 0;
      this->reqId = 0;
   }
   return this;
}

void
Invoke_delete(Invoke *this)
{
   if (this) {
      if (this->conn)
         Connection_delete (this->conn);
      free(this);
   }
}

CORBA_Boolean
Invoke_init (Invoke *this, Exception *ex, IiopObj *o, CorbaMethod *meth)
{
   CORBA_Boolean Return = CORBA_False;
   if (meth) {
      this->methods = meth;
      this->obj = o;
      this->conn = Connection_new (o);
      if (this->conn && Connection_connect (this->conn, ex))
         Return = CORBA_True;
   }
   return Return;
}

CORBA_Boolean
Invoke_invoke(Invoke *this,Exception *ex,char *name,void **argv)
{
   CORBA_Boolean Return = CORBA_False;
   CorbaMethod *mt;
   int argc;
   MessageHeader he;

   if (this->methods == 0) {
      Exception_set (ex, ErrorCode_NOT_INIT, "Invoke object not initialized");
      return Return;
   } else if (name == 0) {
      Exception_set (ex, ErrorCode_MISSING_PARAM, "Invalid name in Invoke");
      return Return;
   }
   for (mt = this->methods; ; mt++)
      if (mt->name == 0) {
         Exception_set (ex, ErrorCode_NO_METHOD_FOUND, name);
         break;
      } else if (strcmp (name, mt->name) == 0) {
         CORBA_ULong offsLenMess;
         CorbaArg *arg;
         Message *msg = Message_new ();
         offsLenMess = GiopHeader (msg, Request);
         Message_putLong (msg, 0);                   /* service context */
         Message_putLong (msg, this->reqId++);       /* request id */
         Message_putBoolean (msg, CORBA_True);       /* response expected */
         Message_encode (msg, ex, &TCD_Principal, this->obj->key);/* obj key */
         Message_encode (msg, ex, &TCD_string, name);  /* operation */
         Message_putLong (msg, 0);                   /* requesting principal */

         Log ("operation = %s, param in {", name);
         if (mt->args) {
            for (argc = 0, arg = mt->args ;
                 arg->type != &TCD_KIND_LAST && arg->mode != END_PARAM;
                 arg++, argc++)
               if (arg->mode == PARAM_IN || arg->mode == PARAM_INOUT) {
                  Message_encode (msg, ex, arg->type, argv[argc]);
                  CORBA_Object_debug (argv[argc], arg->type);
                  if (Exception_isException(ex)) {
                     Message_delete(msg);
                     return Return;
                  }
               }
         }
         Log ("}");
         *((CORBA_ULong *)(&msg->logicBuffer[offsLenMess])) =
                           Message_getSize(msg) - GIOP_HEADERSIZE;
         if (Connection_send (this->conn, ex,
                              msg->logicBuffer, Message_getSize(msg))) {
            Message_delete (msg);
            msg = Message_new();
            if (Connection_recv (this->conn, ex,
                                 msg->logicBuffer, GIOP_HEADERSIZE)) {
               if (!GiopCheckHeader (&he, msg)) {
                  Exception_set (ex, ErrorCode_INVALID_HEADER,
                                     "Error in reception");
               } else if (he.type == MessageError) {
                  Exception_set (ex, ErrorCode_GENERAL_ERROR,
                                     "Error in reception");
               } else {
                  unsigned char *buf =
                            Message_getBuffer (msg,
                                               he.size + GIOP_HEADERSIZE,
                                               he.byteOrder);
                  Log ("receivedv = %d", he.size);
                  buf += GIOP_HEADERSIZE;
                  if (Connection_recv (this->conn, ex, buf, he.size)) {
                     CORBA_ULong context;
                     CORBA_ULong requestId;
                     CORBA_ULong exception;

                     Message_getULong (msg, &context);
                     Message_getULong (msg, &requestId);
                     Message_getULong (msg, &exception);
                     if (exception == NO_EXCEPTION) {
                        if (mt->args) {
                           Log ("param out {");
                           for (argc = 0, arg = mt->args ;
                                arg->type != &TCD_KIND_LAST &&
                                arg->mode != END_PARAM;
                                arg++, argc++)
                              if (arg->mode == PARAM_INOUT) {
                                 Message_decode (msg, ex,
                                                 arg->type, &(argv[argc]),
                                                 CORBA_False);
                                 CORBA_Object_debug (argv[argc], arg->type);
                              } else if (arg->mode == PARAM_OUT) {
                                 Message_decode (msg, ex,
                                                 arg->type, &(argv[argc]),
                                                 CORBA_False);
                                 CORBA_Object_debug (argv[argc], arg->type);
                              }
                           Log ("}");
                        }
                        Return = CORBA_True;
                     } else {
                        void *str = 0;
                        Message_decode (msg, ex, &TCD_string, &str, CORBA_True);
                        if (!Exception_isException(ex)) {
                           Exception_set (ex,ErrorCode_EXC_RESPONSE,(char*)str);
                           free (str);
                        }
                     }
                  }
               }
            }
         }
         Message_delete (msg);
         break;
      }
   return Return;
}

