#include "carr.h"

/* this example code demonstrates how to implement a virtual array that
   manipulates a C array. The code aims for simplicity so there's no
   locking of the C array, which is obviously common for any mawk instance:
   the code assumes a single thread.

   Index is integer between 0 and CARR_SIZE-1. Delete only sets value to 0.
   The iterator always goes between 0 and CARR_SIZE-1.

   */

char carr[CARR_SIZE];

/* lookup: copy a cell of a member if res != NULL; if create_flag is non-zero,
   the index should be created. If result is non-NULL, it must be destroyed.
   Result can be the same as cidx!
   return:
    -1 on error
     0 if index does not exist
     1 if it does exist
   Because we have a static array, we won't ever return 0; also ignore the
   create flag. Return -1 for boundary error.
 */
int carr_find(mawk_state_t *MAWK, mawk_array_t A, const mawk_cell_t *cidx, mawk_cell_t *res, int create_flag)
{
	int idx;
	idx = libmawk_cell2int(MAWK, cidx);
	if ((idx < 0) || (idx >= CARR_SIZE))
		return -1;
	
	if (res != NULL) {
		mawk_cell_destroy(MAWK, res);
		res->type = C_NUM;
		res->d.dval = carr[idx];
	}
	return 1;
}


/* set the value of an element of the array. The val cell may have any type! */
void carr_set(mawk_state_t *MAWK, mawk_array_t A, const mawk_cell_t *cidx, mawk_cell_t *val)
{
	int idx;
	char cval;

	idx = libmawk_cell2int(MAWK, cidx);
	if ((idx < 0) || (idx >= CARR_SIZE))
		return;
	switch(val->type) {
		case C_NUM:
		case C_STRNUM:
		case C_MBSTRN:
			carr[idx] = libmawk_cell2int(MAWK, val);
			break;
		case C_STRING:
			{
				char buff[2];
				libmawk_print_cell(MAWK, val, buff, 2);
				carr[idx] = buff[0];
			}
			break;
		default:
			carr[idx] = 0;
	}
}


/* delete a cell (since our array is static, set the value to 0) */
static void carr_delete(mawk_state_t *MAWK, mawk_array_t A, const mawk_cell_t *idx)
{
	mawk_cell_t zero;
	zero.type = C_NUM;
	zero.d.dval = 0;
	carr_set(MAWK, A, idx, &zero);
}

/* set up an iterator; the iterator state is just an integer index */
typedef struct {
	int idx;
	mawk_cell_t cidx;
} carr_it_t;

void *carr_it_start(mawk_state_t *MAWK, mawk_array_t A)
{
	carr_it_t *i;
	i = malloc(sizeof(carr_it_t));
	i->idx = -1;
	i->cidx.type = C_NUM;
	return i;
}

/* return next element using an iterator (thread safe) */
const mawk_cell_t *carr_it_next(mawk_state_t *MAWK, mawk_array_t A, void *iterator)
{
	carr_it_t *i = iterator;
	i->idx++;
	if (i->idx >= CARR_SIZE)
		return NULL;
	i->cidx.d.dval = i->idx;
	return &i->cidx;
}

/* finish iteration */
void carr_it_stop(mawk_state_t *MAWK, mawk_array_t A, void *iterator)
{
	/* no need to destroy iterator->cidx as it was a number all the time */
	free(iterator);
}

/* NOTE: the above code tries to be readable, thus there's a separate
   integer index an a cell for sotring the return-cell are in the iterator.
   The code could be shorter taking less ram if the iterator was a cell
   whose (int)d.dval stored the index. */

/* the implementation struct that describes how the array is implemented */
array_imp_t carr_imp = {
	/* low level access: find an index, set and delete members */
	carr_find,
	carr_set,
	carr_delete,

	/* use the generic implementation for high level calls, because... */
	mawk_array_clear_generic,
	mawk_array_loop_vector_generic,
	mawk_array_load_generic,

	/* ... the low level iterator is implemented: */
	carr_it_start,
	carr_it_next,
	carr_it_stop
};

/* set up the array as a built-in */
void custom_array_init(mawk_state_t *m)
{
	/* register the new array */
	libmawk_register_array(m, "CARR", &carr_imp);

	/* globals should be zero'd, but to make it absolutely clear: */
	memset(carr, 0, sizeof(carr));
}


