/*ScianAxes.c
  Eric Pepke
  21 February 1993
  Stuff for axes within SciAn

  By default, SciAn only knows about axes X, Y, and Z.  The file .scianAxes
  in the home directory contains additional axes that SciAn should know 
  about.  It is a text file containing several lines, all of the form

  axisName = otherAxisName

  where axisName is an axis to define and otherAxisName is an existing axis.
  For example,

  longitude = x

  Axis names are not sensitive to case.
*/

#include "Scian.h"
#include "ScianTypes.h"
#include "ScianIDs.h"
#include "ScianWindows.h"
#include "ScianScripts.h"
#include "ScianAxes.h"

AxisPtr axes;

#ifdef PROTO
AxisPtr FindNamedAxis(AxisPtr root, char *name)
#else
AxisPtr FindNamedAxis(root, name)
AxisPtr root;
char *name;
#endif
/*Finds the named axis in tree at root, returning it or returning nothing*/
{
    if (root)
    {
	int result;

	result = strcmp2(name, root -> name);
	if (result < 0)
	{
	    /*To the left*/
	    return FindNamedAxis(root -> left, name);
	}
	else if (result > 0)
	{
	    /*To the right*/
	    return FindNamedAxis(root -> right, name);
	}
	else
	{
	    /*Spot on*/
	    return root;
	}
    }
    else
    {
	return (AxisPtr) NULL;
    }
}

#ifdef PROTO
static AxisPtr AddAxisHelper(AxisPtr *rootPtr, char *name, int dimension)
#else
static AxisPtr AddAxisHelper(rootPtr, name, dimension)
AxisPtr *rootPtr;
char *name;
int dimension;
#endif
/*Recursive helper for AddAxis*/
{
    if (*rootPtr)
    {
	int comparison;

	comparison = strcmp2(name, (*rootPtr) -> name);
	if (comparison < 0)
	{
	    /*To the left*/
	    return AddAxisHelper(&((*rootPtr) -> left), name, dimension);
	}
	else if (comparison > 0)
	{
	    /*To the right*/
	    return AddAxisHelper(&((*rootPtr) -> right), name, dimension);
	}
	else
	{
	    /*Spot on, just change dimension*/
	    (*rootPtr) -> dimension = dimension;
	    return *rootPtr;
	}
    }
    else
    {
	/*Needs a new node here*/
	(*rootPtr) = newp(Axis);
	(*rootPtr) -> left = (*rootPtr) -> right = (AxisPtr) NULL;
	(*rootPtr) -> dimension = dimension;
	(*rootPtr) -> name = malloc(strlen(name) + 1);
	strcpy((*rootPtr) -> name, name);
	return *rootPtr;
    }
}

#ifdef PROTO
AxisPtr AddAxis(char *name, int dimension)
#else
AxisPtr AddAxis(name, dimension)
#endif
/*Adds an axis to the axis system.  Only updates dimension if it's there.*/
{
    return AddAxisHelper(&axes, name, dimension);
}

#ifdef PROTO
int FindAxisDimension(char *name)
#else
int FindAxisDimension(name)
char *name;
#endif
/*Returns the dimension of axis name or -1 if not found*/
{
    AxisPtr axis;

    axis = FindNamedAxis(axes, name);
    if (axis)
    {
	return axis -> dimension;
    }
    else
    {
	return -1;
    }
}

#ifdef PROTO
void DeleteAxes(AxisPtr axes)
#else
void DeleteAxes(axes)
AxisPtr axes;
#endif
/*Deletes tree of axes*/
{
    if (axes)
    {
	DeleteAxes(axes -> left);
	DeleteAxes(axes -> right);
	SAFEFREE(axes -> name);
	free(axes);
    }
}

static void PrintAxes(axes)
AxisPtr axes;
{
    if (axes)
    {
	PrintAxes(axes -> left);
	printf("%14s %d\n", axes -> name, axes -> dimension);
	PrintAxes(axes -> right);
    }
}

#ifdef PROTO
void PrintErrorHeader(char *fileName, int line)
#else
void PrintErrorHeader(fileName, line)
char *fileName;
int line;
#endif
/*Prints an error header*/
{
    fprintf(stderr, "Error in file %s, line %d:\n", fileName, line);
}

void InitAxes()
{
    FILE *axesFile;
    int curLine;
    char *s;
    char newAxisName[TEMPSTRSIZE], oldAxisName[TEMPSTRSIZE];
    char fileName[TEMPSTRSIZE];

    axes = 0;
    AddAxis("X", 0);
    AddAxis("Y", 1);
    AddAxis("Z", 2);

    /*Read the axes file*/
    sprintf(fileName, "%s/%s", getenv("HOME"), ".scianAxes");
    curLine = 0;
    axesFile = fopen(fileName, "r");
    if (axesFile)
    {
	while (fgets(tempStr, TEMPSTRSIZE, axesFile))
	{
	    ++curLine;
	    wholeLine = tempStr;
	    s = tempStr;
	    SKIPBLANKS(s);
	    if (*s && *s != '#' && *s != '\n')
	    {
		SHIFTKW(newAxisName, s);
		SKIPBLANKS(s);
		if (*s != '=')
		{
		    PrintErrorHeader(fileName, curLine);
		    ScriptError("An equals (=) is expected after the first axis name\n");
		}
		else
		{
		    int dimension;

		    ++s;
		    SHIFTKW(oldAxisName, s);

		    dimension = FindAxisDimension(oldAxisName);
		    if (dimension >= 0)
		    {
			AddAxis(newAxisName, dimension);
		    }
		    else
		    {
			PrintErrorHeader(fileName, curLine);
			ScriptError("This axis has not been defined");
		    }

		    SKIPBLANKS(s);
		    if (*s && *s != '\n')
		    {
			PrintErrorHeader(fileName, curLine);
			ScriptError("Extraneous stuff after line ignored\n");
		    }
		}
	    }
	}
	fclose(axesFile);
    }
}

void KillAxes()
{
    DeleteAxes(axes);
}