/****************** context.c ******************/
/****************** 1999.6.17 ******************/
#include <stdio.h>
#include <string.h>
#include "context.h"
#include "util.h"

AppContext::AppContext()
{
	names = new List();
	types = new List();
	values = new List();
	name_default = new List();
	type_default = new List();
	value_default = new List();

	set_default_value("h_size","int",(void *)300);
	set_default_value("v_size","int",(void *)200);
}

AppContext::~AppContext()
{
	delete names;
	delete types;
	delete values;
	delete name_default;
	delete type_default;
	delete value_default;
}

int AppContext::search_name(List * list,char * name)
{
	int i,j;
	j = list->get_size();
	for (i = 0;i < j;i++) 
		if (!strcmp((char*)(list->get_item(i)),name)) break;
	return (i<j)? i:-1;
}

int AppContext::set_value(char * _name, char * type, void * data)
{
	int i;
	if((i = search_name(name_default,_name)) != -1) {
		if( !strcmp((char*)type_default->get_item(i),type)) {
			if((i = search_name(names,_name)) != -1)
				values->reset_item(i,data);
			else{
				values->add_item(data);
				types->add_item(type);
				names->add_item(_name);
			}
		} 
		else {
			fprintf(stderr,"Warning: class AppContext: data type mismatch, "
					" variable \"%s\" is a \"%s\" instead of \"%s\"\n",
					name_default->get_item(i),type_default->get_item(i),type);
			return 1;
		}
	}
	else {
		if((i = search_name(names,_name)) != -1)
			values->reset_item(i,data);
		else{
			values->add_item(data);
			types->add_item(type);
			names->add_item(_name);
		}
	}
	return 0;
}

void * AppContext::get_value(char * _name)
{
	int i;
	if((i = search_name(names,_name)) != -1)
		return values->get_item(i);
	else if ((i = search_name(name_default,_name)) != -1)
		return value_default->get_item(i);
	return 	0;
}

char * AppContext::get_value_type(char * _name)
{
	int i;
	if((i = search_name(names,_name)) != -1)
		return (char*)types->get_item(i);
	else if ((i = search_name(name_default,_name)) != -1)
		return (char*)type_default->get_item(i);
	return 	NULL;
}

void AppContext::set_default_value(char * _name, char * type, void * data)
{
	int i;
	if((i = search_name(name_default,_name)) != -1) {
		value_default->reset_item(i,data);
		type_default->reset_item(i,type);
	}
	else{
		name_default->add_item(_name);
		type_default->add_item(type);
		value_default->add_item(data);
	}
}

void AppContext::restore_default(char * _name)
{
	int i;
	if((i = search_name(names,_name)) != -1) {
		values->delete_item(i);
		types->delete_item(i);
		names->delete_item(i);
	}
}

void AppContext::restore_all()
{
	names->delete_all();
	types->delete_all();
	values->delete_all();
}

void AppContext::display_values()
{
	int i,j;
	printf("values:\n");
	j = names->get_size();
	for(i = 0; i<j;i++)
		if(!strcmp((char*)types->get_item(i),"char*")) 
			printf("\"%s\" = \"%s\"\n",names->get_item(i),values->get_item(i));
		else if(!strcmp((char*)types->get_item(i),"int"))
			printf("\"%s\" = %d\n",names->get_item(i),values->get_item(i));
		else
			printf("\"%s\" = 0x%x\n",names->get_item(i),values->get_item(i));
	printf("default values:\n");
	j = name_default->get_size();
	for(i = 0; i<j;i++)
		if(!strcmp((char*)type_default->get_item(i),"char*")) 
			printf("\"%s\" = \"%s\"\n",name_default->get_item(i),value_default->get_item(i));
		else if(!strcmp((char*)type_default->get_item(i),"int"))
			printf("\"%s\" = %d\n",name_default->get_item(i),value_default->get_item(i));
		else
			printf("\"%s\" = 0x%x\n",name_default->get_item(i),value_default->get_item(i));
}

#define BUFFER_LENGTH 200
#define BEGIN 1
#define NAME 2
#define NAME_ESCAPE 4
#define VALUE 3

static int is_blank(char c) { return c==' ' || c==9;}
static int is_end(char c) { return c=='\n' || c == 0;}
static int is_number(char c) {return c<='9' && c>='0';}

static void * my_parser(char *a, char ** type)
{
	char * b;
	int n;
	for(b = a; is_number(*b) && !is_blank(*b) && !is_end(*b);b++);
	if(!(is_blank(*b)||is_end(*b))) {
		for(;!is_blank(*b) && !is_end(*b);b++);
		*b = '\0';
		*type = "char*";
		return (void*)my_strdup(a);
	}
	else {
		*type = "int";
		sscanf(a,"%d",&n);
		return (void*) n;
	}
}

void AppContext::load(FILE * fd)
{
	int i,k;
	long pos;
	char *a,*b,*c,*name,*type;
	void * value;
	char buffer[BUFFER_LENGTH];

	a = buffer;
	pos = 0L;
	for(k = 1;k;){
		fseek(fd,pos,SEEK_SET);
		i = fread(buffer,1,BUFFER_LENGTH-1,fd);
		if (i == 0) break;
		buffer[i] = '\0';
		//printf(buffer);
		b = strchr(buffer,(int)'\n');
		if (b) {
			pos += b - buffer +1;
			*b = '\0';
		}
		else k = 0;

		for(a = buffer;is_blank(*a) && !is_end(*a);a++);
		if (*a == '#' || is_end(*a)) continue;
		for(b = a;!is_blank(*b) && !is_end(*b) && *b != '=';b++);
		if(is_end(*b)) continue;
		c = strchr(b,(int)'=');
		if(!c) continue;
		c++;
		for(;is_blank(*c) && !is_end(*c);c++);
		if(is_end(*c)) continue;
		*b = 0;
		//		printf("name = %s, value = %s",a,c);
		name = my_strdup(a);
		value = my_parser(c,&type);
		set_value(name,type,value);
	}
}

void AppContext::save(FILE * fp, char * header)
{
	int i,j;
	char * type;
	if(header != NULL)
		fprintf(fp,"#%s\n\n",header);

	j = names->get_size();
	for (i = 0;i<j;i++) {
		type = (char*)types->get_item(i);
		if (!strcmp(type,"char*"))
			fprintf(fp,"%s = %s\n",names->get_item(i),values->get_item(i));
		else if (!strcmp(type,"int"))
			fprintf(fp,"%s = %d\n",names->get_item(i),values->get_item(i));
		else fprintf(stderr,"class AppContext: save: type \"%s\" does not be supported yet.\n",type);
	}
}

#undef BUFFER_LENGTH


