/*
 * array.c - Array data types are implemented here.
 *
 * 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"
#include "btree.h"

/* ---------- Methods ---------- */
nsObj array_getClass(nsRef);
nsRef array_setClass(nsRef, nsObj);
void array_Print(nsRef);
nsObj array_setARef(nsRef, nsObj, nsObj);
nsObj array_ARef(nsRef, nsObj);
nsObj array_AddSlot(nsRef, nsObj);

struct nsr_ops array_ops = {
     array_getClass,
     array_setClass,
     array_Print,
     array_setARef,
     array_ARef,
};

int array_ExtendToSize(nsRef, int16);

/* ------------------------------------------------------------------------ */
struct nsArrObjS {
     nsObj classSymbol;
     int32 num_elems;
     int32 max_elems;
     nsObj nso_array[1];
};

#define ARR_STEP_SIZE 5
#define get_aop(nsr)  ((struct nsArrObjS *)(nsr + 1))

/* ------------------------------------------------------------------------ */
nsObj
make_array(int16 num_elems, nsObj initial_value)
{
     nsRef nsr;
     struct nsArrObjS *aop;
     size_t index;
     int16 init_num, i;

     /* init_num leaves space for an extra 5 elements */
     init_num = num_elems + ARR_STEP_SIZE;
     
     /* Error checking, George -gam */
     index = alloc_slot(sizeof(struct nsRefS) +
			sizeof(struct nsArrObjS) +
			(init_num - 1) * sizeof(nsObj), &nsr);

     /* Fill in general information */
     nsr->primclass = PRIMC_ARRAY;
     nsr->ops = &array_ops;

     /* Fill in specific information */
     aop = get_aop(nsr);
     aop->classSymbol = ARRAY_CLASS;
     aop->num_elems = num_elems;
     aop->max_elems = init_num;

     /* Fill in the array */
     for (i = 0; i < num_elems; i++) {
	  aop->nso_array[i] = initial_value;
     }
     
     /* Add type information and return */
     return (index << 2) | REFERENCE_BITS;
}

/* ------------------------------------------------------------------------ */
nsObj
array_getClass(nsRef nsr)
{
     return(0);
}

/* ------------------------------------------------------------------------ */
nsRef
array_setClass(nsRef nsr, nsObj nso)
{
     return(NULL);
}

/* ------------------------------------------------------------------------ */
nsObj
array_setARef(nsRef nsr, nsObj index, nsObj value)
{
     struct nsArrObjS *aop;

     aop = get_aop(nsr);

     /* Type checking first */
     if (!nso_isinteger(index)) {
	  /* Raise an exception here -gam */
	  assert(nso_isinteger(index));
     }

     /* Raise an exception here -gam */
     assert(int_value(index) < aop->num_elems);

     aop->nso_array[int_value(index)] = value;
     return value;
}

/* ------------------------------------------------------------------------ */
nsObj
array_ARef(nsRef nsr, nsObj index)
{
     struct nsArrObjS *aop;

     aop = get_aop(nsr);

     /* Type checking first */
     if (!nso_isinteger(index)) {
	  /* Raise an exception here -gam */
	  assert(nso_isinteger(index));
     }

     /* Raise an exception here -gam */
     assert(int_value(index) < aop->num_elems);

     return aop->nso_array[int_value(index)];
}

/* ------------------------------------------------------------------------ */
void
array_Print(nsRef nsr)
{
     struct nsArrObjS *aop;
     int16 i;
     
     aop = get_aop(nsr);
     fputc('[', stdout);
     fputc(' ', stdout);
     nso_print(aop->classSymbol);
     fputc(':', stdout);
     fputc('\n', stdout);

     for (i = 0; i < aop->num_elems; i++) {
	  fputc('\t', stdout);
	  nso_print(aop->nso_array[i]);
	  if (i < aop->num_elems - 1) fputc(',', stdout);
	  fputc('\n', stdout);
     }

     fputc(']', stdout);

     return;
}

/* ------------------------------------------------------------------------ */
nsObj
array_AddSlot(nsRef nsr, nsObj elem)
{
     struct nsArrObjS *aop;

     aop = get_aop(nsr);

     if (aop->num_elems >= aop->max_elems) {
	  /* Error checking here, George */
	  array_ExtendToSize(nsr, aop->max_elems + 1);
     }

     aop->nso_array[aop->num_elems++] = elem;
     

     return elem;
}

/* ------------------------------------------------------------------------ */
int
array_ExtendToSize(nsRef nsr, int16 len)
{
     assert("Not implemented yet" == (char *)3258);
     return 0;
}
