/*
_____       _    _    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
*/
#include <stdlib.h>
#include <string.h>
#include "corba.h"
#include "message.h"
#include "log.h"

static char *rcsid = "$Id: corba.c,v 1.2 2002/05/06 10:20:21 picoSoft Exp $";
static char *rcsidh = corba_h;

/*
   This variable is used to shutdown gracefully the
   server after the calling of some methods.
   This system does NOT work in multithreading
*/
CORBA_Boolean CORBA_shutdown = CORBA_False;

CORBA_TCKindDesc TCD_null = { tk_null, 0, 0, 0 };
CORBA_TCKindDesc TCD_void = { tk_void, 0, 0, 0 };
CORBA_TCKindDesc TCD_short = { tk_short, 0, 0, 0 };
CORBA_TCKindDesc TCD_long = { tk_long, 0, 0, 0 };
CORBA_TCKindDesc TCD_ushort = { tk_ushort, 0, 0, 0 };
CORBA_TCKindDesc TCD_ulong = { tk_ulong, 0, 0, 0 };
CORBA_TCKindDesc TCD_float = { tk_float, 0, 0, 0 };
CORBA_TCKindDesc TCD_double = { tk_double, 0, 0, 0 };
CORBA_TCKindDesc TCD_boolean = { tk_boolean, 0, 0, 0 };
CORBA_TCKindDesc TCD_char = { tk_char, 0, 0, 0 };
CORBA_TCKindDesc TCD_octet = { tk_octet, 0, 0, 0 };
CORBA_TCKindDesc TCD_any = { tk_any, 0, 0, 0 };
CORBA_TCKindDesc TCD_TypeCode = { tk_TypeCode, 0, 0, 0 };
CORBA_TCKindDesc TCD_Principal = { tk_Principal, 0, 0, 0 };
CORBA_TCKindDesc TCD_objref = { tk_objref, 0, 0, 0 };
CORBA_TCKindDesc TCD_struct = { tk_struct, 0, 0, 0 };
CORBA_TCKindDesc TCD_union = { tk_union, 0, 0, 0 };
CORBA_TCKindDesc TCD_enum = { tk_enum, 0, 0, 0 };
CORBA_TCKindDesc TCD_string = { tk_string, 0, 0, 0 };
CORBA_TCKindDesc TCD_sequence = { tk_sequence, 0, 0, 0 };
CORBA_TCKindDesc TCD_array = { tk_array, 0, 0, 0 };
CORBA_TCKindDesc TCD_alias = { tk_alias, 0, 0, 0 };
CORBA_TCKindDesc TCD_KIND_LAST= { TC_KIND_LAST, 0, 0, 0 };

#define align(p,s) ((s-(p%s))&(s-1))

#define setFeature(x,t,p) { \
   struct tmc { \
      x a; \
      char dummy; \
      x b; \
   } mc; \
   Feature[t].size = sizeof (x); \
   Feature[t].align = (char*) &mc.b - (char*) &mc.a - sizeof(x); \
   Feature[t].isPnt = p; \
}

struct tFeature Feature[(int)TC_KIND_LAST];

void
CORBA_init ()
{
   setFeature(CORBA_Short, tk_short, CORBA_False);
   setFeature(CORBA_Long, tk_long, CORBA_False);
   setFeature(CORBA_UShort, tk_ushort, CORBA_False);
   setFeature(CORBA_ULong, tk_ulong, CORBA_False);
   setFeature(CORBA_Float, tk_float, CORBA_False);
   setFeature(CORBA_Double, tk_double, CORBA_False);
   setFeature(CORBA_Boolean, tk_boolean, CORBA_False);
   setFeature(CORBA_Char, tk_char, CORBA_False);
   setFeature(CORBA_Octet, tk_octet, CORBA_False);
   setFeature(CORBA_String, tk_string, CORBA_True);
   setFeature(CORBA_Any *, tk_any, CORBA_True);
   setFeature(CORBA_TypeCode *, tk_TypeCode, CORBA_True);
   setFeature(CORBA_Principal*, tk_Principal, CORBA_True);
   setFeature(CORBA_Sequence *, tk_sequence, CORBA_True);
   setFeature(CORBA_Alias, tk_alias, CORBA_False);
/*
   setFeature(CORBA_Object_ptr, tk_objref);
   setFeature(CORBA_LongLong, tk_longlong);
   setFeature(CORBA_ULongLong, tk_ulonglong);
   setFeature(CORBA_LongDouble, tk_longdouble);
   setFeature(CORBA_WChar, tk_wchar);
   setFeature(CORBA_WString, tk_wstring);
*/
}

void
CORBA_Object_calcSize (const CORBA_TCKindDesc *k, CORBA_ULong *size)
{
   switch (k->kind) {
   default:
      *size += align (*size, Feature[k->kind].align);
      *size += Feature[k->kind].size;
      break;
   case tk_array:
      if (k->suppl && k->len) {
         int i;
         for (i = 0; i < k->len; i++)
            CORBA_Object_calcSize (k->suppl[0], size);
      }
      break;
   case tk_struct:
      if (k->suppl) {
         int i;
         for (i = 0; k->suppl[i]->kind != TC_KIND_LAST; i++)
             CORBA_Object_calcSize (k->suppl[i], size);
      }
      break;
   }
}


CORBA_TCKindDesc *
CORBA_TCKindDesc_dup (const CORBA_TCKindDesc *tck)
{
    CORBA_TCKindDesc *Return = 
                       (CORBA_TCKindDesc*) malloc (sizeof (CORBA_TCKindDesc));
   if (tck) {
      Return->kind = tck->kind;
      if (tck->name)
         Return->name = strdup(tck->name);
      else
         Return->name = 0;
      if (tck->suppl) {
         int i;
         Return->len =  tck->len;
         for (i = 0; tck->suppl[i]->kind != TC_KIND_LAST; i++)
            ;
         Return->suppl = 
              (CORBA_TCKindDesc**) malloc (sizeof(CORBA_TCKindDesc*) * (i+1));
         for (i = 0; tck->suppl[i]->kind != TC_KIND_LAST; i++)
            Return->suppl[i] = CORBA_TCKindDesc_dup (tck->suppl[i]);
         Return->suppl[i]->kind = TC_KIND_LAST;
      } else {
         Return->suppl = (CORBA_TCKindDesc **) 0;
      }
   } else {
      Return->kind = tk_null;
      Return->suppl = (CORBA_TCKindDesc **) 0;
      Return->len =  0;
   }
   return Return;
}

void
CORBA_TCKindDesc_delete (CORBA_TCKindDesc *tck)
{
   if (tck) {
      if (tck->suppl) {
         int i;
         for (i = 0; tck->suppl[i]->kind != TC_KIND_LAST; i++)
            CORBA_TCKindDesc_delete (tck->suppl[i]);
         CORBA_TCKindDesc_delete (tck->suppl[i]);
         free (tck->suppl);
      }
      if (tck->name)
         free (tck->name);
      free (tck);
   }
}

void *
CORBA_Object_new (const CORBA_TCKindDesc *k, int size)
{
   void *Return = 0;

   switch (k->kind) {
   case tk_null:
   case tk_void:
      break;
   case tk_char:
   case tk_octet:
      Return = malloc (sizeof (CORBA_Char));
      break;
   case tk_short:
   case tk_ushort:
      Return = malloc (sizeof (CORBA_Short));
      break;
   case tk_long:
   case tk_ulong:
   case tk_enum:
      Return = malloc (sizeof (CORBA_Long));
      break;
   case tk_float:
      Return = malloc (sizeof (CORBA_Float));
      break;
   case tk_double:
      Return = malloc (sizeof (CORBA_Double));
      break;
   case tk_boolean:
      Return = malloc (sizeof (CORBA_Boolean));
      break;
   case tk_string:
      if (size > 0)
         Return = malloc (size);
      else
         Return = 0;
      break;
   case tk_Principal:
      {
         CORBA_Principal *p = (CORBA_Principal *) (Return =
                              malloc (sizeof(CORBA_Principal)));
         if (size > 0) {
            p->size = size;
            p->data =  malloc (p->size);
         } else {
            p->size = 0;
            p->data = 0;
         }
      }
      break;
   case tk_struct:
      {
         CORBA_ULong s = 0;
         CORBA_Object_calcSize (k, &s);
         Return = malloc (s);
         break;
      }
   case tk_sequence:
      {
         CORBA_Sequence *seq = (CORBA_Sequence *) (Return =
                                malloc (sizeof(CORBA_Sequence)));
         if (k->suppl) {
            int i;

            seq->count = size;

            switch (k->suppl[0]->kind) {
            case tk_short:
            case tk_long:
            case tk_ushort:
            case tk_ulong:
            case tk_float:
            case tk_double:
            case tk_boolean:
            case tk_char:
            case tk_octet:
               seq->data = malloc (Feature[k->suppl[0]->kind].size * size);
               break;
            default:
               seq->data = malloc (sizeof(void*) * size);
               for (i = 0; i < size; i++)
                  seq->data[i]=CORBA_Object_new (k->suppl[0],k->suppl[0]->len);
            }
         } else {
            seq->count = 0;
            if (size > 0)
               seq->data = malloc (size);
            else
               seq->data = 0;
         }
      }
      break;
   case tk_TypeCode:
      {
         CORBA_TypeCode *tc = (CORBA_TypeCode *) (Return =
                              malloc (sizeof(CORBA_TypeCode)));
         tc->repositoryId = 0;
         if (k->suppl)
            tc->kdesc = CORBA_TCKindDesc_dup (k->suppl[0]);
         else
            tc->kdesc = 0;
      }
      break;
   case tk_any:
      {
         CORBA_Any *any = (CORBA_Any *) (Return = malloc (sizeof(CORBA_Any)));
         any->tcOut = 0;
         if (k->suppl) {
            any->tcIn = k->suppl[0];
            any->data = CORBA_Object_new (k->suppl[0], k->suppl[0]->len);
         } else {
            any->tcIn = 0;
            if (size > 0)
               any->data = malloc (size);
            else
               any->data = 0;
         }
      }
      break;
   case tk_array:
      if (k->suppl && k->len) {
         CORBA_ULong s = 0;
         CORBA_Object_calcSize (k, &s);
         Return = malloc (s);
         memset (Return, '\0', s);
         break;
      }
      break;
   case tk_alias:
         Return = malloc (sizeof(CORBA_Alias));
         memset (Return, 0, sizeof(CORBA_Alias));
      break;
   /* not implemented yet */
   case tk_longlong:
   case tk_ulonglong:
   case tk_objref:
   case tk_union:
   case tk_except:
   case tk_wstring:
   case tk_longdouble:
   case tk_wchar:
   default:
      break;
   }
   return Return;
}

static void
CORBA_Object_struct_delete (CORBA_Octet *this, const CORBA_TCKindDesc *k,
                            CORBA_ULong *offs)
{
   int i;
   if (k->suppl)
      for (i = 0; k->suppl[i]->kind != TC_KIND_LAST; i++)
         if (k->suppl[i]->kind == tk_struct)
            CORBA_Object_struct_delete (this, k->suppl[i], offs);
         else if (k->suppl[i]->kind == tk_array) {
            int j;
            for (j = 0; j < k->suppl[i]->len; j++)
               CORBA_Object_struct_delete (this, k->suppl[i], offs);
         } else {
            *offs += align (*offs, Feature[k->suppl[i]->kind].align);
            if (Feature[k->suppl[i]->kind].isPnt)
               CORBA_Object_delete (*(void **)&this[*offs], k->suppl[i]);
            CORBA_Object_calcSize (k->suppl[i], offs);
         }
}

void
CORBA_Object_delete (void *this, const CORBA_TCKindDesc *k)
{
   if (this == 0)
      return;

   switch (k->kind) {
   case tk_null:
   case tk_void:
   case tk_char:
   case tk_octet:
   case tk_short:
   case tk_ushort:
   case tk_long:
   case tk_ulong:
   case tk_enum:
   case tk_float:
   case tk_double:
   case tk_boolean:
   case tk_string:
      break;
   case tk_Principal:
      {
         CORBA_Principal *p = (CORBA_Principal *) this;
         if (p->size > 0 && p->data)
            free (p->data);
      }
      break;
   case tk_struct:
      if (k->suppl) {
         CORBA_ULong start = 0;
         CORBA_Object_struct_delete ((CORBA_Octet *)this, k, &start);
      }
      break;
   case tk_sequence:
      {
         CORBA_Sequence *seq = (CORBA_Sequence *) this;
         if (k->suppl && seq->count > 0 && seq->data) {
            unsigned int i;
            switch (k->suppl[0]->kind) {
            case tk_short:
            case tk_long:
            case tk_ushort:
            case tk_ulong:
            case tk_float:
            case tk_double:
            case tk_boolean:
            case tk_char:
            case tk_octet:
               break;
            default:
               for (i = 0; i < seq->count; i++)
                  CORBA_Object_delete (seq->data[i], k->suppl[0]);
               break;
            }
            free (seq->data);
         }
      }
      break;
   case tk_TypeCode:
      {
         CORBA_TypeCode *tc = (CORBA_TypeCode *) this;
         if (tc) {
            if (tc->repositoryId)
               free (tc->repositoryId);
            if (tc->kdesc)
               CORBA_TCKindDesc_delete (tc->kdesc);
         }
      }
      break;
   case tk_any:
      {
         CORBA_Any *any = (CORBA_Any *) this;
         if (any) {
            if (any->data) {
               if (any->tcIn)
                  CORBA_Object_delete (any->data, any->tcIn);
               else if (any->tcOut)
                  CORBA_Object_delete (any->data, any->tcOut);
            }
            if (any->tcOut)
               CORBA_TCKindDesc_delete (any->tcOut);
         }
      }
      break;
   case tk_array:
      if (k->suppl && k->len) {
         int j;
         CORBA_ULong offs = 0;
         for (j = 0; j < k->len; j++)
             CORBA_Object_struct_delete (this, k->suppl[0], &offs);
      }
      break;
   case tk_alias:
      {
         CORBA_Alias *alias = (CORBA_Alias *) this;
         if (alias) {
            if (alias->repositoryId)
               free (alias->repositoryId);
            if (alias->name)
               free (alias->name);
         }
      }
      break;
   /* not implemented yet */
   case tk_longlong:
   case tk_ulonglong:
   case tk_objref:
   case tk_union:
   case tk_except:
   case tk_wstring:
   case tk_longdouble:
   case tk_wchar:
   default:
      break;
   }
   if (this)
      free (this);
}

void
CORBA_Object_debug (void *this, const CORBA_TCKindDesc *k)
{
   switch (k->kind) {
   case tk_null:
   case tk_void:
      Log ("null =(null)");
      break;
   case tk_char:
   case tk_octet:
      if (this)
         Log ("char =%c", *(char *)this);
      else
         Log ("char =(null)");
      break;
   case tk_boolean:
      if (this)
         Log ("bool =%d", *(CORBA_Short *)this);
      else
         Log ("bool =(null)");
      break;
   case tk_short:
      if (this)
         Log ("short=%d", *(CORBA_Short *)this);
      else
         Log ("short=(null)");
      break;
   case tk_ushort:
      if (this)
         Log ("ushrt=%u", *(CORBA_UShort *)this);
      else
         Log ("ushrt=(null)");
      break;
   case tk_long:
      if (this)
         Log ("long =%ld", *(CORBA_Long *)this);
      else
         Log ("long =(null)");
      break;
   case tk_ulong:
      if (this)
         Log ("ulong=%lu", *(CORBA_ULong *)this);
      else
         Log ("ulong=(null)");
      break;
   case tk_enum:
      if (this)
         Log ("enum =%ld", *(CORBA_Long *)this);
      else
         Log ("enum =(null)");
      break;
   case tk_float:
      if (this)
         Log ("float=%g", *(CORBA_Float *)this);
      else
         Log ("float=(null)");
      break;
   case tk_double:
      if (this)
         Log ("doubl=%g", *(CORBA_Float *)this);
      else
         Log ("doubl=(null)");
      break;
   case tk_string:
      if (this)
         Log ("strin=%.128s", (CORBA_String)this);
      else
         Log ("strin=(null)");
      break;
   case tk_Principal:
      if (this) {
         CORBA_Principal *p = (CORBA_Principal *) this;
         Log ("princ=[%.*s]", p->size, p->data);
      } else
         Log ("princ=(null)");
      break;
   case tk_struct:
      if (this) {
         if (k->suppl) {
            CORBA_ULong offs = 0;
            CORBA_Octet *data = this;
            int i;
            for (i = 0; k->suppl[i]->kind != TC_KIND_LAST; i++) {
               if (Feature[k->suppl[i]->kind].align) {
                  offs += align (offs, Feature[k->suppl[i]->kind].align);
                  if (Feature[k->suppl[i]->kind].isPnt)
                     CORBA_Object_debug (*(void**)&data[offs], k->suppl[i]);
                  else
                     CORBA_Object_debug (&data[offs], k->suppl[i]);
                  CORBA_Object_calcSize (k->suppl[i], &offs);
               }
            }
         }
      } else
         Log ("struct=(null)");
      break;
   case tk_sequence:
      if (this) {
         CORBA_Sequence *seq = (CORBA_Sequence *) this;
         if (k->suppl) {
            unsigned int i;
            for (i = 0; i < seq->count; i++)
               CORBA_Object_debug (seq->data[i], k->suppl[0]);
         }
      } else
         Log ("sequnc=(null)");
      break;
   /* not implemented yet */
   case tk_any:
   case tk_TypeCode:
   case tk_longlong:
   case tk_ulonglong:
   case tk_objref:
   case tk_union:
   case tk_array:
   case tk_alias:
   case tk_except:
   case tk_wstring:
   case tk_longdouble:
   case tk_wchar:
   default:
      break;
   }
}
