/*****
 * Test.m
 *
 *	Main program for a console test pgm.
 *
 *****/
#import "ObjDB.h"
#import <streams/streams.h>
#include <stdio.h>
#define TRUE -1
#define FALSE !TRUE
char commands[39][10] = {
	"open","close","quit","load","dump","restore",
	"and","or","xor","not","all","find","status",
	"structure","show","print","read","list","add",
	"delete","update","init","dekey","keydb","keyfld",
	"cache","alloc","isns","keys","keytbl","help",
	"isn","fields","last","!","isntables","search","gripe",""};
enum ops {
	OPEN,CLOSE,QUIT,LOAD,DUMP,RESTORE,
	AND,OR,XOR,NOT,ALL,FIND,STATUS,
	STRUCTURE,SHOW,PRINT,READ,LIST,ADD,
	DELETE,UPDATE,INIT,DEKEY,KEYDB,KEYFLD,
	CACHE,ALLOC,ISNS,KEYS,KEYTBL,HELP,
	ISN,FIELDS,LAST,SHELL,ISNTABLES,SEARCH,GRIPE,BAD
};

	ObjDB		*myDB;

int main(argc, argv)
	int argc;
	char *argv[];
{
	NXTypedStream *typedStream;
	char *get_word();
	char desc[128], value[256], dbname[256], tmp_str[256], load_file[256];
	char cmd[256];
	int i,j,k,l,m, get_cmd(), *Isns, *Last, kount=0;
	void prt_cmds();
	int get_prompt(), num_words(), which_cmd();
	int toupper();
	union	{
		int num;
		char str[128];
		} u;
	FILE *fptr, *dfd_file;
	int	opened = FALSE;
	float dFrac;
	FIELD	*myField;
		
	struct	{
	char last_name[12];
	char first_name[12];
	long	phone_no;
	char		state[3];
	}	rec;
	
	if (argc == 2)	{
		strcpy(dbname,argv[1]);
		strcpy(desc,dbname);
		strcat(desc,".dta");
		goto open;
		}
	else	{
		opened = FALSE;
		strcpy(dbname,"NULL");
		}
	while(1)
	{
	printf("%s : %d > ",dbname,kount++);
	switch(get_cmd(cmd))	{
	case SHELL:
		if( num_words(cmd) < 2)
		{
			strcat(cmd," ");
			printf("Enter Shell Command : ");
			gets(value);
			strcat(cmd,value);
		}
		strcpy(desc,get_word(-1,cmd));
		system(desc);
		break;
	case INIT:
		dFrac = 0.75;
		if( num_words(cmd) < 2)
			get_prompt("Enter Data Base Name",dbname);
		else
			strcpy(dbname,get_word(1,cmd));
/*		get data fraction here if num_words == 3	*/
		strcpy(load_file,dbname);
		strcat(load_file,".dfd");
		if((dfd_file = (FILE *)fopen(load_file,"r")) == NULL)
		{
			printf("Descriptor file for Database %s not located\n",dbname);
			break;
		}
/* check if this already exists and warn */
		myDB  = [[ObjDB alloc] init:dbname data_use_fraction:dFrac];
		if ([myDB loadDFD:dfd_file] == NULL)
		{
			/*	Loading of data was not  */
			printf("Error in reading Descriptor file for database %s\n",dbname);
			break;
		}	
		/*	Write out the object , i.e. close existing database */
		[myDB close];
		strcpy(desc,dbname);
		strcat(desc,".dta");
		typedStream = NXOpenTypedStreamForFile(desc,NX_WRITEONLY);
		NXWriteRootObject(typedStream,myDB);
    	NXCloseTypedStream(typedStream);
		printf("DB Archived to %s\n",desc);
		[myDB free];
		opened = FALSE;
		goto open;
		break;
	case OPEN:
	/*	read in the archived object	, i.e. open an existing database */
		if (opened)
		{
			printf("Must close first\n");
			break;
		}
		if( num_words(cmd) != 2)
			get_prompt("Enter Data Base Name",dbname);
		else
			strcpy(dbname,get_word(1,cmd));
		strcpy(desc,dbname);
		strcat(desc,".dta");
open:		if(!(typedStream = NXOpenTypedStreamForFile(desc,NX_READONLY)))
		{
			printf("Database %s not located\n",dbname);
			strcpy(dbname,"NULL");
			break;
		}
		myDB = NXReadObject(typedStream);
    	NXCloseTypedStream(typedStream);
		opened = TRUE;
		break;
	case ADD:
		if (!opened)
		{
			printf("Must open first\n");
			break;
		}
		j = [myDB numberFlds];
		k = 0;
		strcpy(desc,"");
		for (i=0; i<j; i++)	{
			myField = [myDB getFldDesc:i];
			printf("%s : ",myField->name);
			switch (myField->kind)	{
			case 'I':
			case 'L':
				gets(tmp_str);
				sscanf(tmp_str,"%d",&u.num);
				for (l=0;l<4;l++)
					value[k++] = u.str[l];
				strcat(desc,myField->abbrev);
				strcat(desc,",4,");
				break;
			case 'A':
				gets(tmp_str);
				l = strlen(tmp_str);
				for(m=0;m<l;m++)
					value[k++] = tmp_str[m];
				strcat(desc,myField->abbrev);
				sprintf(tmp_str,",%d,",l);
				strcat(desc,tmp_str);
				break;
			}
		}
		printf("Added Isn %d\n",
			[myDB addData:(char *)value:desc]);
		break;
	case DEKEY:
		if (!opened)
		{
			printf("Must open first\n");
			break;
		}
		get_prompt("This will remove all keys, are you sure (y/n)?",desc);
		if(toupper(desc[0]) == 'Y')
			[myDB unKeyDB];
		break;	
	case AND:
		if (!opened)
		{
			printf("Must open first\n");
			break;
		}
		[myDB andIsns];
		printf("Found %d matches\n",[myDB getListCount]);
		break;	
	case OR:
		if (!opened)
		{
			printf("Must open first\n");
			break;
		}
		[myDB orIsns];
		printf("Found %d matches\n",[myDB getListCount]);
		break;	
	case XOR:
		if (!opened)
		{
			printf("Must open first\n");
			break;
		}
		[myDB xorIsns];
		printf("Found %d matches\n",[myDB getListCount]);
		break;	
	case NOT:
		if (!opened)
		{
			printf("Must open first\n");
			break;
		}
		[myDB notIsns];
		printf("Found %d matches\n",[myDB getListCount]);
		break;	
	case DUMP:
		if (!opened)
		{
			printf("Must open first\n");
			break;
		}
		if([myDB getListCount] == 0)
		{
			printf("No records selected, Dump aborted\n");
			break;	
		}
		if (num_words(cmd) != 2)
			get_prompt("Enter File Name to Dump to",desc);
		else
			strcpy(desc,get_word(1,cmd));
		[myDB dumpIsns:[myDB getIsnList] toFile:desc];
		break;	
	case KEYDB:
		if (!opened)
		{
			printf("Must open first\n");
			break;
		}
		[myDB keyDB];
		break;	
	case KEYFLD:
		if (!opened)
		{
			printf("Must open first\n");
			break;
		}
		get_prompt("Enter field abbrev to key",desc);
		[myDB setKeyField:desc];
		break;	
	case RESTORE:
		if (opened)
		{
			printf("Must close first\n");
			break;
		}
		dFrac = 0.75;
		if( num_words(cmd) < 2)
			get_prompt("Enter Data Base Name",dbname);
		else
			strcpy(dbname,get_word(1,cmd));
/*		get data fraction here if num_words == 3	*/
		strcpy(load_file,dbname);
		strcat(load_file,".dfd");
		if((dfd_file = (FILE *)fopen(load_file,"r")) == NULL)
		{
			printf("Descriptor file for Database %s not located\n",dbname);
			break;
		}
		myDB  = [[ObjDB alloc] init:dbname data_use_fraction:dFrac];
		if ([myDB loadDFD:dfd_file] == NULL)
		{
			/*	Loading of data was not  */
			printf("Error in reading Descriptor file for database %s\n",dbname);
			break;
		}	
		if( num_words(cmd) != 3)
			get_prompt("Enter Dump File Name",value);
		else
			strcpy(value,get_word(2,cmd));
		[myDB loadDBfromFile:value];
		opened = TRUE;
		break;	
	case FIND:
		if (!opened)
		{
			printf("Must open first\n");
			break;
		}
		if( num_words(cmd) < 2)
			get_prompt("Enter keyed field",desc);
		else
			strcpy(desc,get_word(1,cmd));
		if(!strcasecmp(desc,"ALL"))
		{
			strcpy(desc,"*");
			strcpy(value,"ALL");			
		}
		else
		if( num_words(cmd) < 3)
			get_prompt("Enter value to search for in field",value);
		else
			strcpy(value,get_word(-2,cmd));
		[myDB getIsnListforField:desc value:value];
		printf("Found %d matches\n",[myDB getListCount]);
		break;
	case SEARCH:
		if (!opened)
		{
			printf("Must open first\n");
			break;
		}
		if( num_words(cmd) < 2)
			get_prompt("Enter field",desc);
		else
			strcpy(desc,get_word(1,cmd));
		if( num_words(cmd) < 3)
			get_prompt("Enter Operator",tmp_str);
		else
			strcpy(tmp_str,get_word(2,cmd));
		if( num_words(cmd) < 4)
			get_prompt("Enter Value",value);
		else
			strcpy(value,get_word(-3,cmd));
			
		[myDB getIsnListforField:desc value:value operator:tmp_str];
		printf("Found %d matches\n",[myDB getListCount]);
		break;	
	case PRINT:
		if (!opened)
		{
			printf("Must open first\n");
			break;
		}
/*	Print Options */
		if( num_words(cmd) < 2)
			get_prompt("Enter option",tmp_str);
		else
			strcpy(tmp_str,get_word(1,cmd));
		switch(which_cmd(tmp_str))	{
	case ISNS:
		Isns = [myDB getIsnList];
		for(i=0;i<*Isns;i++)
			{
			printf("------------Record %d ----------\n", Isns[i+1]);
			[myDB prtRecAtIsn:Isns[i+1]];
			}
		break;	
	case ISN:
		if( num_words(cmd) < 3)
			get_prompt("Enter isn",tmp_str);
		else
			strcpy(tmp_str,get_word(2,cmd));
		sscanf(tmp_str,"%d",&i);
		[myDB prtRecAtIsn:i];
		break;	
	case KEYTBL:
		if (!opened)
		{
			printf("Must open first\n");
			break;
		}
		get_prompt("Enter keyed field",desc);
		[myDB prtKeyTableFor:desc];
		break;
	case HELP:
		printf("Print Options are: isns, isn, keytable\n");
		break;
	default:
		break;
		}
		break;	
	case LIST:
		if (!opened)
		{
			printf("Must open first\n");
			break;
		}
/*	List Options */
		if( num_words(cmd) < 2)
			get_prompt("Enter option",tmp_str);
		else
			strcpy(tmp_str,get_word(1,cmd));
		switch(which_cmd(tmp_str))	{
	case ISNS:
		Isns = [myDB getIsnList];
		for(i=0;i<*Isns;i++)
			{
			if((i-(i/10)*10) == 0)	printf("\n");
			printf("%5d ",Isns[i+1]);
			}
			printf("\n");
		break;
	case FIELDS:
		get_prompt("Enter keyed field to list",desc);
		printf("# value	- count for key field %s\n",desc);
		[myDB listKeysForField:desc];
		break;	
	case LAST:
		Last = [myDB getLastList];
		for(i=0;i<Last[0];i++)
			{
			if((i-(i/10)*10) == 0)	printf("\n");
			printf("%5d ",Last[i+1]);
			}
			printf("\n");
		break;
	case HELP:
		printf("List options are:  isns, fields, last\n");
		break;
	default:
			break;
		}
		break;
	case UPDATE:
		if (!opened)
		{
			printf("Must open first\n");
			break;
		}
/*	Update Options */
		if( num_words(cmd) < 2)
			get_prompt("Enter option",tmp_str);
		else
			strcpy(tmp_str,get_word(1,cmd));
		switch(which_cmd(tmp_str))	{
	case ISNS:
		Isns = [myDB getIsnList];
		strcpy(desc,"");
		if( num_words(cmd) < 3)
			get_prompt("Enter field abbrev",load_file);
		else
			strcpy(load_file,get_word(2,cmd));
if ((myField =[myDB getFldDesc:[myDB getFldNumForAbbrev:load_file]]) == NULL)
	{
		printf("Field %s not in data base\n",load_file);
		Isns = [myDB pushList:0];
		break;
		}
			printf("Enter replacement value for field %s: ",myField->name);
			switch (myField->kind)	{
			case 'I':
			case 'L':
				gets(tmp_str);
				sscanf(tmp_str,"%d",&u.num);
				strcat(desc,myField->abbrev);
				strcat(desc,",4,");
				break;
			case 'A':
				gets(u.str);
				l = strlen(u.str);
				strcat(desc,myField->abbrev);
				sprintf(tmp_str,",%d,",l);
				strcat(desc,tmp_str);
				break;
			}
		for(i=0;i<*Isns;i++)
			[myDB updateDataAtIsn:Isns[i+1] with:(char *)u.str
				describedBy:desc];			
		break;
	case ISN:
		if( num_words(cmd) < 3)
			get_prompt("Enter isn",tmp_str);
		else
			strcpy(tmp_str,get_word(2,cmd));
		sscanf(tmp_str,"%d",&i);
		j = [myDB numberFlds];
		for (k=0; k<j; k++)	{
			myField = [myDB getFldDesc:k];
			printf("%s, ",myField->name);
			switch (myField->kind)	{
			case 'I':
			case 'L':
				strcpy(desc,myField->abbrev);
				strcat(desc,",4,");
		[myDB getData:(char *)u.str atIsn:i describedBy:desc];
		printf(" %s = %d , Replace with <cr> : ",myField->abbrev,u.num);
				gets(tmp_str);
				if (strlen(tmp_str) == 0) break;
				sscanf(tmp_str,"%d",&u.num);
			[myDB updateDataAtIsn:i with:(char *)u.str
				describedBy:desc];			
				break;
			case 'A':
				strcpy(desc,myField->abbrev);
				strcat(desc,",128,");
		[myDB getData:(char *)u.str atIsn:i describedBy:desc];
		printf(" %s = %s , Replace with <cr> : ",myField->abbrev,u.str);
				gets(tmp_str);
				if (strlen(tmp_str) == 0) break;
				strcpy(u.str,tmp_str);
			[myDB updateDataAtIsn:i with:(char *)u.str
				describedBy:desc];			
				break;
			}
		}
		break;
	case HELP:
	default:
		printf("Options are isns for mass update and isn for single\n");
		break;
	}
		break;
	case CLOSE:
		if (!opened)
		{
			printf("Must open first\n");
			break;
		}	
		[myDB close];
		strcpy(desc,dbname);
		strcat(desc,".dta");
		typedStream = NXOpenTypedStreamForFile(desc,NX_WRITEONLY);
		NXWriteRootObject(typedStream,myDB);
    	NXCloseTypedStream(typedStream);
		printf("DB Archived to %s\n",desc);
		[myDB free];
		opened = FALSE;
		strcpy(dbname,"NULL");
		break;
	case DELETE:
		if (!opened)
		{
			printf("Must open first\n");
			break;
		}
/*	Delete Options */
		if( num_words(cmd) < 2)
			get_prompt("Enter option",tmp_str);
		else
			strcpy(tmp_str,get_word(1,cmd));
		switch(which_cmd(tmp_str))	{
	case ISN:
		if( num_words(cmd) < 3)
			get_prompt("Enter isn",tmp_str);
		else
			strcpy(tmp_str,get_word(2,cmd));
		sscanf(tmp_str,"%d",&i);
		[myDB deleteDataAtIsn:i];
		break;	
	case ISNS:
		Isns = [myDB getIsnList];
		for(i=0;i<*Isns;i++)
			{
			if((i-(i/10)*10) == 0)	printf("\n");
			printf("%5d ",Isns[i+1]);
			}
			printf("\n");
		break;
	case HELP:
		printf("Delete options are: isn, isns\n");
		break;
	default:
		break;
		}
		break;
	case LOAD:
		if (!opened)
		{
			printf("Must open first\n");
			break;
		}
		if( num_words(cmd) < 2)
			get_prompt("Enter File to load from",load_file);
		else
			strcpy(load_file,get_word(1,cmd));
	fptr = (FILE *)fopen(load_file,"r");
		printf("Here we should enter descriptor string and input format\n");
	i = 0;
	while(1)	{
		fscanf(fptr,"%s %s %ld\n",rec.last_name,rec.first_name,&rec.phone_no);
		printf("Added isn %d: %s , %s\n",
			[myDB addData:(char *)rec.last_name:"LN,12,FN,12,PH,L,"],
			rec.last_name,rec.first_name);
		if (feof(fptr) != 0) break;
		i++;
		}
		break;
	case SHOW:
		if (!opened)
		{
			printf("Must open first\n");
			break;
		}	
		if( num_words(cmd) != 2)
			get_prompt("Enter option",tmp_str);
		else
			strcpy(tmp_str,get_word(1,cmd));
		switch(which_cmd(tmp_str))	{
		case STRUCTURE:
			[myDB prtStructure];
			break;
		case STATUS:
			[myDB status];
			break;
		case CACHE:
			[myDB prtCacheStats];
			break;
		case ALLOC:
			[myDB dumpSpace];
			break;
		case ISNTABLES:
			[myDB dumpIsns];
			break;
		case HELP:
			printf("The options are: structure, status,\n");
			printf("                 cache, alloc, isntables.\n");
			break;
		default:
			[myDB prtStructure];
			[myDB status];
			[myDB prtCacheStats];
		get_prompt("Do you wish to see alloc tables?",desc);
		if(toupper(desc[0]) == 'Y')
			[myDB dumpSpace];
		get_prompt("Do you wish to see isn tables?",desc);
		if(toupper(desc[0]) == 'Y')
			[myDB dumpIsns];
		break;
		}
		break;
	case READ:
	/*	Read  */
		if (!opened)
		{
			printf("Must open first\n");
			break;
		}	
		printf("Try to read records\n");
		printf("**This should be for general format from descriptor\n");
		j = [myDB numberIsns];
		for (i=0;i<j;i++)
		{
			strcpy(rec.last_name,"");
			strcpy(rec.first_name,"");
			if ([myDB getData:(char *)rec.last_name atIsn:i
				describedBy:"LN,12,FN,6,"] != NULL)
			printf("%d) %s , %s\n",i,
				rec.last_name,rec.first_name);
		}
		break;
	case QUIT:
		if (opened)	{
			get_prompt("Data base open, save changes (y/n)",tmp_str);
			if (toupper(tmp_str[0]) == 'Y')	{
				[myDB close];
				strcpy(desc,dbname);
				strcat(desc,".dta");
				typedStream = NXOpenTypedStreamForFile(desc,NX_WRITEONLY);
				NXWriteRootObject(typedStream,myDB);
    			NXCloseTypedStream(typedStream);
				printf("DB Archived to %s\n",desc);
				[myDB free];
				}
		}	
		exit(0);
		break;
	case HELP:
		prt_cmds();
		break;
	case GRIPE:
		gripe();
		break;
	default:
		printf("Command %s not recognized\n",cmd);
		kount--;
		break;
	}
}
	
}

int gripe()
{
	char gripe_msg[128];
	char sys_msg1[128];
	char sys_msg2[128] = "cat .gripe_msg | mail -s ObjDB_Gripe woo@ornl.gov; /bin/rm .gripe_msg";
	
	printf("Enter complaint or alloclade : ");
	gets(gripe_msg);
	sprintf(sys_msg1,"echo %s > .gripe_msg",gripe_msg);
	system(sys_msg1);
	system(sys_msg2);
	return TRUE;
}

int get_cmd(str)
	char *str;
{
	int which_cmd();
	char *cmd, *get_word();
	
	gets(str);
	cmd = get_word(0,str);
	return(which_cmd(cmd));
}

int which_cmd(cmd)
	char *cmd;
{
	int i, strlen(), strcmp();
	
	for (i=0; strlen(commands[i]) > 0; i++)
		if (!strcmp(cmd,commands[i])) return i;
	return 99;
}

void prt_cmds()
{
	int i, strlen();
	
	printf("Commands are: ");
	for (i=0; strlen(commands[i]) > 0; i++)
		{
			if ((i-(i/10)*10) == 0) printf("\n");
			printf("%s, ",commands[i]);
		}
	printf("\n");
	return;
}

int get_prompt(prompt,value)
	char *prompt, *value;
{
	int num_words();
		
		printf("%s : ",prompt);
		gets(value);
			
	return (num_words(value));
}

int num_words(str)
	char *str;
{
	int i = 0;
	char *ptr;
	
	ptr = str;
	
	while (TRUE)
		{
			while(*ptr == ' ')	ptr++;	/* skip leading blanks */
			if (*ptr == '\0' || *ptr == '\n') return i;
	  		while(*ptr != ' ' && *ptr != '\0' && *ptr != '\n' ) ptr++;
			i++;
	  	}
}

char *get_word(n,str)
	int n;
	char *str;
{
	char *strcpy();
	static char dummy[256];
	char *ptr = str;
	int i = 0;
	int j = 0;
	
	strcpy(dummy,"");
		
	/* special case neg argument means rest of line starting at nth arg. */
	if ( n < 0)
	{
	n = -n;
	while (TRUE)
		{
			while(*ptr == ' ')	ptr++;	/* skip leading blanks */
			if (i == n) break;
			if (*ptr == '\0' || *ptr == '\n') return "";
	  		while(*ptr != ' ' && *ptr != '\0' && *ptr != '\n' ) ptr++;
			i++;
	  	}
			while(*ptr != '\0')
				{
					if(*ptr == '\n') break;
					dummy[j++] = *ptr++;
				}
				
			dummy[j] = '\0';
	return dummy;
	}
	else while (TRUE)
		{
			while(*ptr == ' ')	ptr++;	/* skip leading blanks */
			if (i == n) break;
			if (*ptr == '\0' || *ptr == '\n') return "";
	  		while(*ptr != ' ' && *ptr != '\0' && *ptr != '\n' ) ptr++;
			i++;
	  	}
			while(*ptr != ' ')
				{
					if(*ptr == '\0') break;
					if(*ptr == '\n') break;
					dummy[j++] = *ptr++;
				}
				
			dummy[j] = '\0';
	return dummy;
}
