////////////// Demonstration of Typed Data Values //////////////////
//Compile as a project with TYPEDEM2.CPP and TYPESALL.CPP.  The file 
//TYPESALL.H must be in the include directory.

#include <string.h>
#include <stdio.h>
#include <typesall.h>

class node{ 
	friend class database;
	node* next; value* val;
	node(){next=NULL;val=NULL;}
	node(node* nxt,value* v){next=nxt;val=v;}
	~node(){delete val;}};
class database{
 protected:
	node root;
	int insert(value* val);
 public:
	database();
	~database();
	int assert(char* namestr);
	int assert(char* namestr,int val);
	int assert(char* namestr,long val);
	int assert(char* namestr,float val);
	int assert(char* namestr,double val);
	int assert(char* namestr,long double val);
	int assert(char* namestr,char* val);
	void retract(char* namestr);
	value* valueof(char* namestr);
	int count();
	void show();
	};

///////Code for the database
//enter values into the database
database::database(){root=node();};
database::~database(){
	node *dad,*son=root.next;
	while(son){dad=son;son=son->next;delete dad;}
	}

int database::assert(char* namestr){
	retract(namestr);
	value* tempptr=(value*)new value(namestr);
	if (!tempptr) return 0;
	if (!tempptr->valid()) {delete tempptr; return 0;}
	insert(tempptr); return 1;}
int database::assert(char* namestr,int val){
	retract(namestr);
	value* tempptr=(value*)new ival(namestr,val);
	if (!tempptr) return 0;
	if (!tempptr->valid()) {delete tempptr; return 0;}
	insert(tempptr); return 1;}
int database::assert(char* namestr,long val){
	retract(namestr);
	value* tempptr=(value*)new lval(namestr,val);
	if (!tempptr) return 0;
	if (!tempptr->valid()) {delete tempptr; return 0;}
	insert(tempptr); return 1;}
int database::assert(char* namestr,float val){
	retract(namestr);
	value* tempptr=(value*)new fval(namestr,val);
	if (!tempptr) return 0;
	if (!tempptr->valid()) {delete tempptr; return 0;}
	insert(tempptr); return 1;}
int database::assert(char* namestr,double val){
	retract(namestr);
	value* tempptr=(value*)new dval(namestr,val);
	if (!tempptr) return 0;
	if (!tempptr->valid()) {delete tempptr; return 0;}
	insert(tempptr); return 1;}
int database::assert(char* namestr,long double val){
	retract(namestr);
	value* tempptr=(value*)new ldval(namestr,val);
	if (!tempptr) return 0;
	if (!tempptr->valid()) {delete tempptr; return 0;}
	insert(tempptr); return 1;}
int database::assert(char* namestr,char* val){
	retract(namestr);
	value* tempptr=(value*)new sval(namestr,val);
	if (!tempptr) return 0;
	if (!tempptr->valid()) {delete tempptr; return 0;}
	insert(tempptr); return 1;}

int database::insert(value* newval){
	node *n=&root;
	while(n->next && strcmp(newval->name(),n->next->val->name())>0){
		n=n->next;}
	node* newnode=new node(n->next,newval); if(!newnode) return 0;
	n->next=newnode; 
	return 1;}

//remove a specific value from the database
void database::retract(char* namestr){	if(!namestr) return;
	node *vdead,*v=&root;
	while(v->next && strcmp(namestr,v->next->val->name())){
		v=v->next;}
	vdead=v->next;
	if(vdead){v->next=vdead->next; delete vdead;}}

//retrieve pointer to value associated with a specific nametag
value* database::valueof(char* namestr){
	node *v=root.next;
	while(v && strcmp(namestr,v->val->name())){v=v->next;};
	return v->val;}

//return count of values asserted into the database
int database::count(){
	int cnt=0;
	for(node* v=root.next;v;v=v->next){cnt++;};
	return cnt;};

//display the database
void database::show(){
	int N=count();
	printf("Database contains %d value%s:\n",N,(N==1)? "":"s");
	for(node* v=root.next;v;v=v->next){
		printf("\t%s=\t%s[%s]\n",
				v->val->name(),v->val->asstring(),v->val->typename());}
	printf("\n");
	};

database* db;
int dbchg=0;
int N=12345;
long L=1234567890;
float F=1234.567;
double D=1234567890.12345;
long double LD=123456789012.345678;
char S[]="Now is the time for all good programmers...";
char* nullstr=NULL;
void addsamples(){
	db->assert("int",N);
	db->assert("long",L);
	db->assert("float",F);
	db->assert("double",D);
	db->assert("ldoubl",LD);
	db->assert(nullstr,N);
	db->assert("null",nullstr);
	db->assert("string",S);
	db->assert("username","Superman");
	db->assert("weakness","Kryptonite");
	dbchg=1;
	printf("Sample values added.\n");}

void reportval(char* name){
	value* val=db->valueof(name);
	if (val){printf("%s=%s\n",name,val->asstring());}
	else {printf("No value has been entered for <%s>.\n",name);}}

void deleteval(char* name){
	value* val=db->valueof(name);
	if (val){
		db->retract(name);dbchg=1;
		printf("<%s> deleted.\n",name);}
	else {printf("No value has been entered for <%s>.\n",name);}}

int qmark(char* name){
	int lastch=strlen(name)-1;
	if(name[lastch]!='?') return 0;
	name[lastch]=0; return 1;}

//The following function returns args like the command line
//global values to ease conversion to argc and argv[] later
char argline[80], *argptr, arg[3][80], delims[]=" \t,";
int argcnt;
int getargs(){
	printf("Action?  "); gets(argline);	//get user input
	argptr=strtok(argline,delims);	//initialize parsing function
	for(argcnt=1; argcnt<3&&argptr; argcnt++) {
		strcpy(arg[argcnt],argptr);
		argptr=strtok(NULL,delims);}
	return argcnt>1;}

void main(){
	printf("Database test begins-----\n");
	db=new database();

	while(getargs()){
		char* name=arg[1]; char* valstr=(argcnt>2)? arg[2]:"";
		if(strcmp(name,"/samples")==0)	{addsamples();}
		else if(strcmp(name,"/show")==0) {db->show();}
		else if(qmark(name))					{reportval(name);}
		else if(name[0]=='-')				{deleteval(name+1);}
		else if(strlen(valstr)==0)			{reportval(name);}
		else {db->assert(name,valstr); dbchg=1;
			printf("<%s> added.\n",name);};
		if(dbchg) {db->show(); dbchg=0;}
		}
	printf("Test complete.\n\n");}
