/*
 * © Copyright 1996-2012 ECMWF.
 * 
 * This software is licensed under the terms of the Apache Licence Version 2.0
 * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. 
 * In applying this licence, ECMWF does not waive the privileges and immunities 
 * granted to it by virtue of its status as an intergovernmental organisation nor
 * does it submit to any jurisdiction.
 */

#include "mars.h"

static mempool varmem = {
	1, /* 1 page */
	1, /* clear */
};

#define STACK_SIZE 10
#define FASTNEW(type)        (type*)fast_new(sizeof(type),&varmem)
#define FASTDEL(x)           fast_delete(x,&varmem)

static variable *vars = NULL;

static int top = 0;
static variable stack[STACK_SIZE+1];

err push_scalar(double d)
{
	if(top == STACK_SIZE)
	{
		marslog(LOG_EROR,"Stack is full");
		return -2;
	}
	stack[top].scalar = true;
	stack[top].val    = d;
	stack[top].name   = NULL;
	top++;
	return NOERR;
}

err push_named_scalar(char *name, double d)
{
	if(top == STACK_SIZE)
	{
		marslog(LOG_EROR,"Stack is full");
		return -2;
	}
	stack[top].scalar = true;
	stack[top].val    = d;
	stack[top].name   = name;
	top++;
	return NOERR;
}

err push_fieldset(fieldset *f)
{
	if(top == STACK_SIZE)
	{
		marslog(LOG_EROR,"Stack is full");
		return -2;
	}
	stack[top].scalar = false;
	stack[top].fs     = f;
	stack[top].name   = NULL;
	top++;
	return NOERR;
}

err push_named_fieldset(char *name, fieldset *f)
{
	if(top == STACK_SIZE)
	{
		marslog(LOG_EROR,"Stack is full");
		return -2;
	}
	stack[top].scalar = false;
	stack[top].fs     = f;
	stack[top].name   = name;
	top++;
	return NOERR;
}

err push(variable *v)
{
	abort();
	return 0;
}

variable *pop()
{
	if(top == 0)
	{
		marslog(LOG_EROR,"Stack is empty");
		return NULL;
	}
	return &stack[--top];
}

variable *stack_top()
{
	return &stack[top-1];
}

variable *find_variable(const char *name)
{
	variable *w = vars;
	while(w)
	{
		if(w->name == name) return w;
		w = w->next;
	}
	return NULL;
}

err name_variable(variable *v,char *name)
{
	abort();
	return 0;
}

static void free_variables(int code,void *data)
{
	while(vars)
		free_variable(vars);
}

variable *new_variable(const char *name,fieldset *f,double d)
{
	variable *w = find_variable(name);
	variable *v  = FASTNEW(variable);

	if(vars == 0)
		install_exit_proc(free_variables,0);

	v->name = name?strcache(name):NULL;

	if(f)
	{
		v->fs   = f;
		v->scalar = false;
		f->refcnt++;
		if(save_fieldset(f))
		{
			FASTDEL(v);
			return NULL;
		}
	}
	else
	{
		v->scalar = true;
		v->fs  = NULL;
		v->val = d;
	}

	if(w) free_variable(w);

	v->next = vars;
	vars = v;
	return v;
}

void free_variable(variable *v)
{
	variable *w = vars;
	variable *z = NULL;
	while(w)
	{
		variable* n = w->next;

		if(w == v)
		{
			if(z)
				z->next = v->next;
			else 
				vars = v->next;
			if(v->name)
				strfree(v->name);
			if(v->fs) free_fieldset(v->fs);
			FASTDEL(v);
		}
		z = w;
		w = n;
	}
}

