/*
 * nsobj.c - Implementation of nsObj type, the basic NS Object.
 *
 * Copyright (C) 1997, George Madrid
 * All rights reserved.
 */

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

#include "config.h"
#include "nsobj.h"
#include "nsref.h"
#include "nsrefarr.h"
#include "utils.h"

/* ---------- Some globals ---------- */
nsObj SYMBOL_CLASS;
nsObj REAL_CLASS;
nsObj STRING_CLASS;
nsObj FRAME_CLASS;
nsObj ARRAY_CLASS;

/* ------------------------------------------------------------------------ */
int
ns_initialize()
{
     return(nso_initialize());
}

/* ------------------------------------------------------------------------ */
int
nso_initialize()
{
     /* Initialize stuff that needs to be there before we start */
     init_ref_array(10000);	/* 10,000 is probably not enough -gam */
     init_symbol_tree();

     /* We need to boot strap the 'symbol symbol. */
     SYMBOL_CLASS = make_symbol_symbol();
     /* ...and the 'string symbol */
     STRING_CLASS = make_string_symbol();

     /* Now that we have 'symbol and 'string, we can make other symbols */
     REAL_CLASS = make_symbol("real");
     FRAME_CLASS = make_symbol("frame");
     ARRAY_CLASS = make_symbol("array");
     
     /* Add some error checking here -gam */
     return(0);
}

/* ------------------------------------------------------------------------ */
int
nso_primclass(nsObj nso)
{
     nsRef nsr;
     
     if (nso % 2 == IMMED_BITS) {
	  return PRIMC_IMMEDIATE;
     }

     /* It's a reference type, so look it up */
     nsr = find_index(ref_index(nso));
     return nsr_primclass(nsr);
}

/* ------------------------------------------------------------------------ */
nsObj
nso_classof(nsObj nso)
{
     /*
      * This has to return type nsObj because the return value could be a user
      * defined class.  Therefore, it returns a symbol.
      */
     nsRef nsr;

     /* This is just plain weird.  What IS the class of something */
     /* 'char, 'bool, 'string, 'array, 'frame, 'function, 'symbol,
      * or special */

     
}

/* ------------------------------------------------------------------------ */
int
nso_isarray(nsObj nso)
{
     return nso_primclass(nso) == PRIMC_ARRAY;
}
   
int
nso_isframe(nsObj nso)
{
     return nso_primclass(nso) == PRIMC_FRAME;
}

int
nso_isbinary(nsObj nso)
{
     return nso_primclass(nso) == PRIMC_BINARY;
}

int
nso_isinteger(nsObj nso)
{
     /* If first two bits are 00. */
     return (nso % 4) == INTEGER_BITS;
}

int
nso_isboolean(nsObj nso)
{
     /* If first three bits are 010 */
     return (nso % 8) == BOOLEAN_BITS;
}

int
nso_ischaracter(nsObj nso)
{
     /* If first three bits are 110 */
     return (nso % 8) == CHARACTER_BITS;
}


int
nso_issymbol(nsObj nso)
{
     nsRef nsr;
     
     /* First check it's a reference */
     if ((nso % 2) != ALLREFS_BITS) return 0;

     nsr = find_index(ref_index(nso));
     return SYMBOL_CLASS == nsr_class(nsr);
}

int
nso_isreal(nsObj nso)
{
     nsRef nsr;
     
     /* First, check it's a reference */
     if ((nso % 2) != ALLREFS_BITS) return 0;

     nsr = find_index(ref_index(nso));
     return REAL_CLASS == nsr_class(nsr);
}

int
nso_isstring(nsObj nso)
{
     nsRef nsr;
     
     if ((nso % 2) != ALLREFS_BITS) return 0;

     nsr = find_index(ref_index(nso));
     return STRING_CLASS == nsr_class(nsr);
}

/* ------------------------------------------------------------------------ */
nsObj
nso_setARef(nsObj arr, nsObj index, nsObj value)
{
     nsRef nsr;

     /* Throw an exception -gam */
     assert((arr % 2) == ALLREFS_BITS);

     nsr = find_index(ref_index(arr));

     /* Throw an exception -gam */
     assert(nsr->ops->setARef);

     return nsr->ops->setARef(nsr, index, value);
}

/* ------------------------------------------------------------------------ */
nsObj
nso_ARef(nsObj arr, nsObj index)
{
     nsRef nsr;

     /* Throw an exception -gam */
     assert((arr % 2) == ALLREFS_BITS);

     nsr = find_index(ref_index(arr));

     /* Throw an exception -gam */
     assert(nsr->ops->ARef);

     return nsr->ops->ARef(nsr, index);
}

/* ---------------------------------------------------------------------- */
void _Print(nsObj nso) { nso_print(nso); }

void
nso_print(nsObj nso)
{
     if ((nso % 2) == ALLREFS_BITS) {
	  nsRef nsr;
	  nsr = find_index(ref_index(nso));
	  nsr->ops->Print(nsr);
	  /* It's a reference object, do it -gam */
	  return;
     }

     /* Is it an integer? */
     if ((nso % 4) == INTEGER_BITS) {
	  printf("%ld ", nso>>2);
     }
     else if ((nso % 8) == CHARACTER_BITS) {
	  /* This won't work with high-word characters -gam */
	  printf("$%c", (char)(nso >> 3));
     }
     else if ((nso % 8) == BOOLEAN_BITS) {
	  if (nso >> 3) {
	       printf("true ");
	  }
	  else {
	       printf("nil ");
	  }
     }
     else {
	  /* Some sort of internal error here -gam */
     }
}

/* ------------------------------------------------------------------------ */
nsObj
nso_AddArraySlot(nsObj nso, nsObj elem)
{
     nsRef nsr;

     /* Add exception -gam */
     assert(nso_isarray(nso));

     nsr = find_index(ref_index(nso));
     return array_AddSlot(nsr, elem);
}
