/* ScianNames.c: John R. Murray. Various string - ID number association
 * mechanisms. This stuff is extremely dusty and largely unused
 * and unusable, with the primary exception of GetInternalString.
 */

#include "Scian.h"
#include "ScianTypes.h"
#include "ScianNames.h"
#include "ScianGarbageMan.h"
#include "ScianWindows.h"
#include "ScianObjWindows.h"
#include "ScianDialogs.h"
#include "ScianIDsDefiner.h"

IDArrayStruct IDArray[MAXIDNUM];

/* global Name tree, associates string names with ID numbers */
NameNodePtr	IDsTree = (NameNodePtr) NIL;

/* ComparePtrs returns true iff two pointers address the same location */
#define ComparePtrs(obj1,obj2) ( (void *) (obj1) == (void *) (obj2))

/* AssignPtr assigns one pointer to another regardless of types pointed to */
#define AssignPtr(p1,p2) ( (void *) (p1) = (void *) (p2))

/* id 0="undefined", id 1 to MAXPREDEF..=predefined, >MAXPRE.. "user" */
NameTyp	SaveLastID = MAXPREDEFIDNUM;

/* forward define */
void	InitIDsTree();

void    FreeNameTree(node)
NameNodePtr     *node;
{
    if (! *node)
	return;

    FreeNameTree( &((*node)->left) );       /* clear the subtrees */
    FreeNameTree( &((*node)->right) );
    if ((*node)->stringPtr)
    {
	free((*node)->stringPtr);       /* clear this node's string */
    }
    free(*node);                    /* free this node */
    *node = (NameNodePtr) NIL;
}

void	InitNames()
{
    int i;

    for (i = 0; i < MAXIDNUM; ++i)
    {
	IDArray[i].str = NIL;
	IDArray[i].thing = NULLOBJ;
    }
    InitIDsTree();
#ifdef DEBUG
    PrintIDTree();
#endif
}

extern long globalRefCount;

extern int deleteCount;
extern int trivialDeleteCount;
extern int noDeleteCount;
extern int missedDeleteCount;

void	KillNames()
{
    int	i;

    FreeNameTree(&IDsTree);

    deleteCount = deleteCount; /* dummy statements to put a dbx trap on */
    deleteCount = deleteCount;
}

NameNodePtr    NewNameNode(str,id)
char    *str;
NameTyp    id;
/* NewNameNode:    creates a new node for the internal name tree */
{
    NameNodePtr	newNode;

    if (!(newNode = (NameNodePtr) malloc(sizeof(NameNode)) ))
    {
	OMErr();
	return (NameNodePtr) NIL;
    }
    /* newNode->stringPtr = str; */
    if(!(newNode->stringPtr = (char *) malloc(strlen(str)+1) ))
    {
	OMErr();
	return (NameNodePtr) NIL;
    }
    strcpy(newNode->stringPtr,str);
    newNode->id = id;
    newNode->left = (struct NameNodeStr *) NIL;
    newNode->right = (struct NameNodeStr *) NIL;
    IDArray[id].str = newNode->stringPtr;
    return newNode;
}

NameTyp    InternalNameToID(whichTree, namestr, theComp)
NameNodePtr    *whichTree;
char    	namestr[];
int    	(* theComp)();

/* NameToID:    given string name, find the ID of a thing. If string is not
	found, insert it in the tree, with new ID */
{
    NameNodePtr	*runner;
    Bool	notdone = true;
    int		cmpval;

    runner = whichTree;
    while(notdone)
    {
	if (! *runner)
	{
	    notdone = false;
	}
	else if (0 == (cmpval = theComp((*runner)->stringPtr,namestr)) )
	{
	    /* found it */
	    notdone = false;
	}
	else if (cmpval > 0)
	{
	    /* change runner, continue */
	    runner = &(*runner)->left;
	}
	else /* cmpval < 0 */
	{
	    /* change runner, continue */
	    runner = &(*runner)->right;
	}
    }
    if (*runner)
    {
	return (*runner)->id;
    }
    else
    {
	return 0;
    }
}

char numberBuffer[20];

char    *IDToName(id)
NameTyp    id;
/* IDToName:    given thing's ID, find the string name. Returns null string if
	not found */
{
    if (IDArray[id].str)
    {
	return IDArray[id].str;
    }
    else
    {
	sprintf(numberBuffer, "%d", id);
	return numberBuffer;
    }
}

void    InternalDefineName(whichTree,namestr,id)
NameNodePtr    *whichTree; /* pointer to the tree pointer */
char    *namestr;
NameTyp    id;
/* DefineName:    given string name and id no., associate them with each other.
	This will either create a new NameNode, or alter an old one. */
{
    NameNodePtr	*runner;
    Bool	notdone = true;
    int		cmpval;

    if (id >= MAXIDNUM)
    {
	ReportError("InternalDefineName","Internal Error: ID number too large");
	return;
    }

    runner = whichTree;
    while(notdone)
    {
	if (! *runner)
	{
	    /* new node */
	    if (!(*runner = NewNameNode(namestr,id)))
		return;		/* ran out of memory */
	    notdone = false;
	}
	else if (0 == (cmpval = strcmp((*runner)->stringPtr,namestr)) )
	{
	    /* found old association, redefine it */
	    /* NOTE: have to define what happens if IDArr contains
		more than just stringPtr */
	    /* NOTE: there's a hole here through which you could
		throw away memory */
	    (*runner)->id = id;
	    IDArray[id].str = malloc(strlen(namestr) + 1);
	    if (IDArray[id].str == NIL)
	    {
		OMErr();
		return;
	    }
	    strcpy(IDArray[id].str, namestr);
	    notdone = false;
	}
	else if (cmpval > 0)
	{
	    runner = &(*runner)->left;
	}
	else /* cmpval < 0 */
	{
	    runner = &(*runner)->right;
	}
    }
}

void    DefineID(namestr, id)
char    *namestr;
NameTyp    id;
/* DefineID:    like DefineName above, only using a different tree */
{
    InternalDefineName(&IDsTree, namestr, id);
}


void    PrintNameNode(node, depth)
NameNodePtr    node;
int depth;
{
    int i;

    if (!node) return;
    PrintNameNode(node->left, depth+1);
    for(i=0; i<depth; ++i)
    {
	printf(" ");
    }
    printf("str=\"%s\", id=%ld\n", node->stringPtr, node->id);
    PrintNameNode(node->right, depth+1);
}

void	PrintIDTree()
/* print names and assoc. id #'s of variable ID tree */
{
    PrintNameNode(IDsTree, 0);
}

void TestIDsTree()
{
    char s[256];
    char str[256];
    NameTyp id;

    fprintf(stderr, "testing GetInternalIDs, type a Var or Method number.\n");
    while (gets(s))
    {
	if(1 == sscanf(s, "%s", str))
	{
	    fprintf(stderr, "looking for %s.\n", str);
	    id = GetInternalID(str);
	    fprintf(stderr, "found %s, it is %ld.\n", str, id);
	}
    }
    fprintf(stderr, "done.\n");
}

void InitIDsTree()
{
    ParseScianIDs();
}

/* old version, not using the auto-written ScianIDsDefiner.c */
#if 0
void	InitIDsTree()
{
    FILE *IDsFile;
    char s[256];
    char str[256];
    NameTyp id;

    IDsTree = (NameNodePtr) NIL;

    /* attempt to open the file */
    IDsFile = fopen("ScianIDs.h", "r");
    if (! IDsFile)
    {
	return;
    }

    /* read a line of the file */
    while (fgets(s, 256, IDsFile))
    {
	if(2 == sscanf(s, "#define %s %ld", str, &id))
	{
	    DefineID(str, id);
	}
    }
}
#endif

/* external defnition */
int strcmp2(char *, char *);

NameTyp	GetInternalID(str)
char	*str;
{
    return InternalNameToID(&IDsTree, str, strcmp2);
}

char *GetInternalString(num)
NameTyp num;
{
    return IDToName(num);
}

