/*
 * context class program copyright (C) 2009 - 2013 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.
 */

#ifndef __CONTEXT_H
#define __CONTEXT_H

#define	cxpush(cx, nd)	(cx->misc_stack = Cons(nd, cx->misc_stack))
#define cxpop(cx)	(cx->misc_stack = cx->misc_stack->Cdr())

class Context;

extern Context* CXNode;

class Context {
private:
	Context* next;

public:
	Node*	inherit;
	
	Node*	env_stack;	
	Node*	env;

	Node*	misc_stack;

#define MAX_INT_STACK	128
	long long int_stack[MAX_INT_STACK];
	int	int_stackp;

#define MAX_FLOAT_STACK	128
	long double	float_stack[MAX_FLOAT_STACK];
	int	float_stackp;

#define MAX_COMPLEX_STACK	128
	std::complex<long double> complex_stack[MAX_FLOAT_STACK];
	int	complex_stackp;

	std::string token;
	int	tokenflag;
	
	List*	module;
	Node*	modulename;

	std::string selfname;
	FILE*	ioin;
	FILE*	ioout;

	Node*	ode;
	Node*	integral;

	Context(List* m, Node* mname) {
		inherit = Nil;
		
		env_stack = Nil; 
		int_stackp = 0; 
		float_stackp = 0; 
		complex_stackp = 0; 
		misc_stack = Nil;
		env = Nil->Cons(Nil);

		next = CXNode;
		CXNode = this;
		token = "";
		tokenflag = 0;
		
		module = m;
		modulename = mname;

		selfname = "WORLD";
		
		ioin = stdin;
		ioout = stdout;
		
		ode = Nil;
		integral = Nil;
	}
	
	~Context(){
		Context* cxp;
		if (CXNode == this) {
			CXNode = CXNode->next;
			return;
		}
		for (cxp = CXNode; cxp != NULL; cxp = cxp->next) {
			if (cxp->next == this) {
				cxp->next = next;
				return;
			}
		}
	}

	Context* Next() { return next; }

	void Merge(Context* cx2) {
		env_stack = Append(env_stack, cx2->env_stack);
		if (tokenflag) token = cx2->token;
//printf("context merge "); env_stack->print(); printf("\n");
//printf("context merge cx2 "); cx2->env_stack->print(); printf("\n");
	}

	void Clear();

	void CutAll();	
};

extern void PrintContext();
extern void PopContext(Context* c);
extern void ClearAllContext();

#endif


