#include <assert.h>
#include <string.h>
#include <yafl_usr.h>
#include <yafl_rnt.h>
/*********************************************************/
minimal_dual YD_CHAR     =  {-1, -1,  
                             sizeof(char), 
                             sizeof(minimal_dual),
                             0, 0, 0, 0, 0, "CHAR", NULL, NULL, NULL,
                             NULL, NULL, NULL};
minimal_dual YD_INT      =  {-1, -1, 
                             sizeof(yint), 
                             sizeof(minimal_dual),
                             0, 0, 0, 0, 0, "INTEGER", NULL, NULL, NULL,
                             NULL, NULL, NULL};
minimal_dual YD_REAL     =  {-1, -1, 
                             sizeof(double),  
                             sizeof(minimal_dual),
                             0, 0, 0, 0, 0, "REAL", NULL, NULL, NULL,
                             NULL, NULL, NULL};
minimal_dual YD_BOOL     =  {-1, -1,  
                             sizeof(int), 
                             sizeof(minimal_dual),
                             0, 0, 0, 0, 0, "BOOLEAN", NULL, NULL, NULL,
                             NULL, NULL, NULL};
minimal_dual YD_VIRTUAL  = {-5, -5,
                            0, 0, 
                            0, 0, 0, 0, 1, "?", NULL, NULL, NULL,                           
                            NULL, NULL, NULL};

minimal_dual *YDP_CHAR =  &YD_CHAR;
minimal_dual *YDP_INT  =  &YD_INT;  
minimal_dual *YDP_REAL =  &YD_REAL;  
minimal_dual *YDP_BOOL =  &YD_BOOL;
minimal_dual *YDP_VIRT =  &YD_VIRT;
/*********************************************************/
#define FILLER_SIZE 32
/**/
static int filler1[FILLER_SIZE];
/**/
static unsigned used_classes = 0;
/**/
static int filler2[FILLER_SIZE];
/**/
static minimal_dual *classes[MAX_CLASSES];

#define USES_KILL(cl) ((cl)->kill_func != 0 ? 1 : 0)

/*********************************************************/
int find_class_pos YPARAMS2(minimal_dual *, dual)
{
  int i;
  assertp(dual);
  for (i = 0; i < used_classes; i ++)
  {
    if (classes[i] == dual)
      return i;
  }
  assert(0);
}
/*********************************************************/
void register_class YPARAMS2(minimal_dual*,dual)
{
  assert (dual!=NULL);
  if (used_classes < MAX_CLASSES)
  {
    classes[used_classes] = dual;
    used_classes ++;
  }
  else
  {
    printf("MAX_CLASSES=%d\n", MAX_CLASSES);
    assert(0);
  }
}
/*********************************************************/
yint last_class_sig YPARAMS0
{
  return used_classes;
}
/*********************************************************/
yint total_dual_size YPARAMS0
{                   
  yint i, res=0;
  
  for (i=0; i<used_classes; i++)
    res += classes[i]->dual_size;
  return res;
}
/*********************************************************/
minimal_dual * get_class_dual YPARAMS2(int, sig)
{
  int i;
  for (i = 0; i < used_classes; i++)
    if (classes[i]->first_sig == sig)
      return classes[i];
  return NULL;      
}
/*********************************************************/
void dump_class_dictionary YPARAMS0
{
  minimal_dual	*p;
  minimal_dual	*inherited;
  int		i;
  char		a[200];

  emit_stdout("CLASS DICTIONARY\n");
  emit_stdout("================\n\n");

  for (i=0; i< used_classes; i++)
    {
    p = classes[i];

    sprintf (a, "     NAME, MODULE : %s, %s\n", p->class_name, p->module_name);
    emit_stdout(a);

    inherited=(minimal_dual*)(p->inherited);
    if (inherited==NULL) emit_stdout("      INHERITS OF : nothing\n");
    else
        {
        sprintf (a, "       INHERITS OF : %s, %s\n",
                 inherited->class_name, inherited->module_name);
        emit_stdout(a);
        }

    sprintf (a, "FIRST & LAST SIG. : %d, %d\n",
             p->first_sig, p->last_sig);
    emit_stdout(a);

    sprintf (a, "     ELEMENT SIZE : %d\n\n", p->elem_size);
    emit_stdout(a);
    }
}
/*********************************************************/
static int number_class YPARAMS4(minimal_dual *, dual,
                                 int, sig)
{
  int i;

  dual->first_sig = sig;
  for (i=0; i<used_classes; i++)
    if ((minimal_dual *)classes[i]->inherited == dual)
      if (((minimal_dual *)classes[i])->first_sig < 0)
        sig = number_class (classes[i], sig+1);
  dual->last_sig = sig;
  return sig;
}
/*********************************************************/
void number_classes YPARAMS0
{
  int  i, sig, dual_size;

  sig = 0;
/*
  memset(filler1, 0, FILLER_SIZE);
  memset(filler2, 0, FILLER_SIZE);
*/  
  for (i=0; i < used_classes; i++)
    {
      classes[i]->first_sig = -1;
      classes[i]->shadow_count = 0;
    }
  for (i=0; i < used_classes; i++)
    {
      if (classes[i]->first_sig < 0) 
        if (classes[i]->inherited == (obj_ptr) NULL)
          sig = number_class (classes[i], sig)+1;
    }
}
/*********************************************************/
void clear_shadows YPARAMS0
{
  int i;
  if (used_classes > 16 * 1024)
    {
      for (i=0; i < FILLER_SIZE; i++)
        printf ("%08d ", filler1[i]);
      printf ("\n");  
      printf ("Used classes: %d\n", used_classes);
      for (i=0; i < FILLER_SIZE; i++)
        printf ("%08d ", filler2[i]);
      printf ("\n");  
      exit(1);
    }
  for (i=0; i<used_classes; i++)
    classes[i]->shadow_count= 0; 
}
/*********************************************************/
int kill_required YPARAMS0
{
  int i;
  
  for (i = 0; i < used_classes; i++)
    if (USES_KILL(classes[i]))
      if (classes[i]->inst_count != classes[i]->shadow_count)
        return TRUE;
  return FALSE;
}
/*********************************************************/
VOID y_mark_once YPARAMS0
{
  int i, count; 
  obj_ptr **p;
  obj_ptr once_inst;

#ifdef Y_TRACE_GC
  extern FILE * gc_trace;
  
  fprintf (gc_trace, "\n\n\nMarking once items:\n\n");
#endif    
  
  count = 0;
  for (i=0; i < used_classes; i++)
    {    
      if (classes[i]->once_inst != NULL)    
        {
          once_inst = *(classes[i]->once_inst);
          assert (HEADER(once_inst)->dual == classes[i]);
#ifdef Y_TRACE_GC
          fprintf (gc_trace, "Visiting class:%s\n", classes[i]->class_name);
          set_initial();
#endif    
          enter_pool (once_inst);
          count ++;
#ifdef Y_TRACE_GC
          flush_pool();
#else
          if (count % 16 == 0)
            flush_pool();
#endif    
        }
      p = classes[i]->once_tab;
      if (p != NULL)
        {
        while (*p)
          {               
#ifdef Y_TRACE_GC
          set_initial();
#endif    
          enter_pool(**p);
          count ++;
#ifdef Y_TRACE_GC
          flush_pool();
#else
          if (count % 16 == 0)
            flush_pool();
#endif    
          p++;
          }
        }          
    }
  flush_pool();
}
/*********************************************************/
int is_in YPARAMS4(obj_ptr, p, minimal_dual*, m)
{
  int i;

  assert(p != NULL);
/*  printf("pointeur: %d \n", p);
  printf(" dual %d \n", DUAL_OF(p));
  printf("FirstSig: %d\n", FIRST_SIG(p));*/
  i = FIRST_SIG(p);
  if ((i >= m->first_sig) && (i <= m->last_sig))
    return 1;
   else
    return 0;
}
/*********************************************************/
static unsigned dual_dummy_state[DUAL_DUMMY_SIZE];

static void dump_dual_dummy_state YPARAMS0
{
  int i;
  static char buffer[20];
  for (i = 0; i < DUAL_DUMMY_SIZE; i++)
  {
    sprintf(buffer, "%d", dual_dummy_state[i]);
    emit_stdout(buffer);
  }
  emit_stdout("\n");
  emit_stdout("\n");
}
/******************************************************************/
void reserve_dual_dummy YPARAMS4(unsigned, offset, 
                                unsigned, size)
{
  int i;
  int ok;
  ok = 1;
  assert (offset + size <= DUAL_DUMMY_SIZE);
  for (i = 0; i < size; i++)
  {
    if (dual_dummy_state[offset + i] > 0)
      ok = 0;
    dual_dummy_state[offset + i]++;
  }
  if (!ok)
  {
    dump_dual_dummy_state();
    assert(0);
  }
}
/******************************************************************/
void put_dual_dummy YPARAMS8(minimal_dual *, dual,
                            unsigned, offset,
                            unsigned, size,
                            obj_ptr, data)
{
  assertp(dual);
  assertp(data);
  assert (offset + size <= DUAL_DUMMY_SIZE);
  memcpy((dual->dummy) + offset, data, size);
}
/******************************************************************/
void get_dual_dummy YPARAMS8(minimal_dual *, dual,
                            unsigned, offset,
                            unsigned, size,
                            obj_ptr, data)
{
  assertp(dual);
  assertp(data);
  assert (offset + size <= DUAL_DUMMY_SIZE);
  memcpy(data, (dual->dummy) + offset, size);
}

/******************************************************************/
FIELD_INFO *dual_get_field YPARAMS4(minimal_dual *, dual,
                                   int, pos)
{
  FIELD_INFO *field;
  int i;
  assertp(dual);
  assert(pos >= 0);
  field = dual->first_field;
  i = 0;
  while (i < pos)
  {
    assertp(field);
    field = field->next;
    i++;
  }
  return(field);
}

/************************************************************************/
minimal_dual* get_class YPARAMS2(unsigned, num)
{
  assert(num < used_classes);

  return classes[num];
}

/************************************************************************/
void register_as_son YPARAMS2(minimal_dual *,actual)
{
  minimal_dual *father;
  minimal_dual *son;
  int          already_registered;

  assert (actual!=NULL);

  father=actual->inherited;
  
  if (father!=NULL)
    {
    son=father->first_son;
    already_registered=FALSE;

    while (son!=NULL && !(already_registered))
      {
      already_registered=(son!=actual);
      son=son->brother;
      }

    assert (already_registered || (son==NULL));

    if (!(already_registered))
      {
      actual->brother=father->first_son;
      father->first_son=actual;
      }
    }
}
/************************************************************************/
/* To_Delete
void alloc_parallel_dual YPARAMS2(minimal_dual*,dual)
{
  unsigned inh_meth;
  unsigned total;
  minimal_dual *tmp;

  assert (dual!=NULL);

  inh_meth=0;
  tmp=((minimal_dual*)dual->inherited);

  while (tmp!=NULL)
    {
    inh_meth=inh_meth + tmp->original_method_count;
    tmp=((minimal_dual*)tmp->inherited);
    }

  dual->inherited_method_count=inh_meth;

  total=inh_meth + dual->original_method_count;

  if (total>0)
    {
    dual->add_meth_ref=(additional_method_ref*)
                         malloc(sizeof(additional_method_ref)*total);

    assert (dual->add_meth_ref!=NULL);
    }
}
END To_Delete */
