/*
 * Var node program copyright (C) 2009 H.Niwa 
 */

/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.

 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301, USA.
 */

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

#include <string>

#include "syserr.h"

#include "bin_node.h"
#include "var.h"

unsigned int	undefvar = 0;

// __UNDEF__ object
Atom  __UNDEF__area("__UNDEF__");
Node* __UNDEF__ = &__UNDEF__area;



Var::Var(std::string s)
{
	k = VAR;
	varnode = new Undef();
	
	name = s;
}

Node* Var::Val()
{
	Node* np;

	for (np = varnode; ; np = ((Var*)np)->varnode) {
		if (np->kind() != VAR) {
			return np->Val();
		}
	}
}


Undef* Var::GetUndef()
{
	Node* np;
	for (np = varnode; ; np = ((Var*)np)->varnode) {
		if (np->kind() == UNDEF) {
			return (Undef*)np;
		} else if (np->kind() != VAR) {
			syserr("VAR ... not UNDEF");
			exit(-1);
		}
		// if node is a VAR, continue for loop
	}
}


int Var::Set(Node* n)
{
	Node* nval = n;
	Node* np;

	// if specified value is Var Node, set the value of Var.
	if (n->kind() == VAR) {
		nval = ((Var*)n)->Val();
		if (nval->kind() == UNDEF) {
			nval = n;
		}
	}

	// If it is an undefined variable, set a value.
	// If it already have a value, return false.
	for (np = varnode; ; np = ((Var*)np)->varnode) {
		if (np->kind() == UNDEF) {
			((Undef*)np)->Set(nval);
			return 1;
		} else if (np->kind() != VAR) {
			syserr("VAR ... not UNDEF");
			return 0;
		}
		// if node is a VAR, continue for loop
	}
}

int Var::SetForce(Node* n)
{
	Node* np;
	Node* nval = n->Val();

	if (n->kind() == VAR) {
		nval = ((Var*)n)->Val();
		if (nval->kind() == UNDEF) {
			nval = n;
		}
	}

	for (np = varnode; ; np = ((Var*)np)->varnode) {
		if (np->kind() == UNDEF) {
			int r = ((Undef*)np)->Set(nval);
//printf("SetForce "); Val()->print(); printf("\n");
			return r;
		} else if (np->kind() != VAR) {
			syserr("VAR ... not UNDEF");
			return 0;
		}
	}

}

void Var::gcmark()
{
	Node* np;
	extern void GCmark(Node*);

	if (ref) return;

	ref++;

	for (np = varnode; ; np = ((Var*)np)->varnode) {
		GCmark(np);
		if (np->kind() == UNDEF) {
			break;
		} else if (np->kind() != VAR) {
			break;
		}
	}
}

Undef::Undef() 
{
	k = UNDEF; 
	udefno = undefvar++; 
	value = __UNDEF__; 
}

Node* Undef::Val() 
{ 
	extern void CheckTime();
	CheckTime();
	
	if (value != __UNDEF__) {
		if (value == this) {
			syserr("value of undefined var is looped ");
			return Nil;
		}

		CheckTime();

		return value->Val(); 
	} else {
		return this;
	}
}

void Undef::gcmark()
{
	extern void GCmark(Node*);
	
	if (ref) return;

	ref++;

	GCmark(value);
}

