/*ScianMain.c
  Eric Pepke
  Main routines for SciAn
*/

#include "Scian.h"
#include "ScianTypes.h"
#include "ScianArrays.h"
#include "ScianLists.h"
#include "ScianEvents.h"
#include "ScianWindows.h"
#include "ScianObjWindows.h"
#include "ScianObjFunctions.h"
#include "ScianVisWindows.h"
#include "ScianDialogs.h"
#include "ScianDatasets.h"
#include "ScianColors.h"
#include "ScianControls.h"
#include "ScianDrawings.h"
#include "ScianIcons.h"
#include "ScianRecorders.h"
#include "ScianFiles.h"
#include "ScianFileSystem.h"
#include "ScianGarbageMan.h"
#include "ScianScripts.h"
#include "ScianTimers.h"
#include "ScianErrors.h"
#include "ScianIDs.h"
#include "ScianSpaces.h"
#include "ScianPreferences.h"
#include "ScianSciences.h"
#include "ScianSnap.h"
#include "ScianAxes.h"

Bool stuffInited = false;
extern Bool recordEnabled;
extern FILE *curScript;
Bool runningRemote = false;
real missingData = 1.1E37;
real plusInf = 1E37;
real minusInf = -1E37;
Bool demoP = false;
Bool scriptSelectP = false;
Bool abortScriptP = true;

extern Bool runningScript;	/*True iff running script*/

#ifdef GRAPHICS
#ifdef CURSORS4D
/*Cursors*/
Cursor watchCursor = 
    {
	0x07e0,
	0x07e0,
	0x07e0,
	0x07e0,
	0x0810,
	0x1008,
	0x1008,
	0x11cc,
	0x110c,
	0x1108,
	0x1108,
	0x0810,
	0x07e0,
	0x07e0,
	0x07e0,
	0x07e0
    };
Cursor questionCursor = 
    {
	0x0300,
	0x0300,
	0x0000,
	0x0300,
	0x0300,
	0x0300,
	0x0380,
	0x0180,
	0x0070,
	0x0038,
	0x0018,
	0x1818,
	0x1818,
	0x1c38,
	0x0ff0,
	0x07e0
    };
Cursor iconCursor = 
    {
	0xFFFF,
	0xFFFF,
	0xFFFF,
	0xFFFF,
	0xFFFF,
	0xFFFF,
	0xFFFF,
	0xFFFF,
	0xFFFF,
	0xFFFF,
	0xFFFF,
	0xFFFF,
	0xFFFF,
	0xFFFF,
	0xFFFF,
	0xFFFF
    };
#endif
#endif

/*Read states*/
#define RS_FILE		0	/*Read names as file names*/
#define RS_FORMAT	1	/*Read names as formats*/
#define RS_LOG		2	/*Read names as log files*/
#define RS_SCRIPT	3	/*Read names as script files*/
#define RS_DIRECTORY	4	/*Read names as directory files*/

void ParseArgs(argc, argv)
int argc;
char *argv[];
/*Parses the arguments in argc and argv*/
{
    int k;
    char format[256];		/*Current file format*/
    ObjPtr corral;		/*Corral in the datasets window*/
    char *a;
    int readState = RS_FILE;

    strcpy(format, "");

    for (k = 1; k < argc; ++k)
    {
	/*Go through arguments, parsing them*/
	if (readState != RS_FILE)
	{
	    /*Read this argument as a whatever*/
	    switch(readState)
	    {
		case RS_FORMAT:
		    strncpy(format, argv[k], 255);
		    format[255] = 0;
		    break;
		case RS_SCRIPT:
		    if (curScript)
		    {
			fprintf(stderr, "%s: Only one script can be given on the command line.\n", argv[0]);
			exit(-1);
		    }
		    BeginScript(argv[k]);
		    break;
		case RS_LOG:
		    if (strcmp(argv[k], "-") == 0)
		    {
			OpenLogFile((char *) 0);
		    }
		    else
		    {
			OpenLogFile(argv[k]);
		    }
		    break;
		case RS_DIRECTORY:
		    {
			char t[MAXPATHLEN + 1];
			if (chdir(argv[k]) == 0) /* check if valid directory */
			{
			    getwd(t);	/* get expanded name back */
			    GetFileWindow(t);
			    chdir(dirSave);	/* return to original directory */
			}
			else
			{
			    fprintf(stderr, "%s: '%s' is an invalid directory.\n", argv[0], argv[k]);
			    exit(-1);
			}
		    }
		    break;
	    }
	    readState = RS_FILE;
	}
	else if (argv[k][0] == '-')
	{
	    /*It's a switch*/
	    readState = RS_FILE;

	    
	    for (a = &(argv[k][1]); *a; ++a)
	    {
	    switch (*a)
	    {
		case 'f':
		    /*New file format*/
		    readState = RS_FORMAT;
		    break;
		case '1':
		    /*One observer, clock, whatever*/
		    ++a;
		    switch (*a)
		    {
			case 'c':
			case 'C':
			    oneClock = true;
			    break;
			case 'o':
			case 'O':
			    oneObserver = true;
			    break;
			case 'l':
			case 'L':
			    oneLights = true;
			    break;
			case 'r':
			case 'R':
			    oneRenderer = true;
			    break;
			case 'p':
			case 'P':
			    onePalette = true;
			    break;
			default:
			    fprintf(stderr, "%s: Unrecognized object type for -1 flag\n", argv[0]);
			    exit(-1);
		    }
		    break;
		case 's':
		    /*Script to run*/
		    readState = RS_SCRIPT;
		    break;
		case 'S':
		    /*Select in scripts*/
		    scriptSelectP = true;
		    break;
		case 'C':
		    /*Continue in scripts*/
		    abortScriptP = false;
		    break;
		case 'l':
		    /*Open log file*/
		    readState = RS_LOG;
		    break;
		case 'v':
		    /*Enable recording*/
#ifdef GRAPHICS
#ifdef IRIS
		    blanktime(0);
#endif
#endif
		    recordEnabled = true;
		    break;
		case 'd':
		    /*Demo mode*/
		    demoP = true;
		    break;
		case 'o':
		    /*Open a directory*/
		    readState = RS_DIRECTORY;
		    break;
		default:
		    /*Undefined switch*/
		    fprintf(stderr, "%s: Switch %s is undefined.\n", argv[0], argv[k]);
		    exit(-1);
	    }
	    }
	}
	else
	{
	    WinInfoPtr datasetsWindow;
	    /*It must be a file name*/

	    datasetsWindow = DatasetsWindow();

	    SelWindow(datasetsWindow);
	    IdleAllWindows();
	    LongOperation();
	    ReadFile(argv[k], format);
	}
    }
}

Bool handlingSignals = true;

#ifdef SIGNALS
#ifdef PROTO
void SignalHandler(int sig, int code, struct sigcontext *context)
#else
void SignalHandler(sig, code, context)
int sig;
int code;
struct sigcontext *context;
#endif
/*Handles signals*/
{
    if (0 == handlingSignals)
    {
	/*Just expire*/
	return;
    }
    switch(sig)
    {
#ifdef SIGALRM
	case SIGALRM:
	    /*Get some new events*/
	    NewEvents();
	    {
		struct itimerval value, ovalue;
	
		value . it_interval . tv_sec = 0;
		value . it_interval . tv_usec = 0;
		value . it_value . tv_sec = 0;
		value . it_value . tv_usec = 100000L;
		setitimer(ITIMER_REAL, &value, &ovalue);
	    }
	    signal(SIGALRM, SignalHandler);
	    break;
#endif
#ifdef SIGDANGER
	case SIGDANGER:
	    signal(SIGDANGER, SignalHandler);
	    break;
#endif
    }
}
#endif

main(argc, argv)
int argc;
char *argv[];
{
#ifdef MALLOCH
#ifdef M_MXFAST
    mallopt(M_MXFAST, 1024);
#endif
#endif

#ifdef GRAPHICS
#ifdef IRIS
    foreground();
#endif
#endif

#ifdef SIGNALS
    /*Set up signals*/
#ifdef SIGDANGER
    signal(SIGDANGER, SignalHandler);
#endif
#endif

#ifndef GETGDESCAFTER
    GetConfiguration();
#endif
    InitNames();
    InitObjects();
    InitArrays();
    InitLists();
    InitControls();
    InitSciences();
    InitAxes();
    MainWindow();
    ParseArgs(argc, argv);
#ifdef INTERACTIVE
    QueueDevices();
#endif
    InitEvents();
    InitSnapshots();
    MainLoop();
    KillSnapshots();
    KillEvents();
#ifdef INTERACTIVE
    UnqueueDevices();
#endif
    while (logging)
    {
	CloseLogFile();
    }
#ifdef GRAPHICS
#ifdef IRIS
    if (recordEnabled)
    {
	blanktime(40000);
    }
#endif
#endif
    handlingSignals = false;
    DisposeAllWindows();
    KillGlobalFunctions();
    KillRecorders();
    KillPreferences();
    KillColors();
    KillDialogs();
    KillObjFunctions();
    KillVisWindows();
    KillObjWindows();
    KillWindows();
    KillPictures();
    KillVisObjects();
    KillTimers();
    KillSpaces();
    KillFilters();
    KillDatasets();
    KillGeometry();
    KillDrawings();
    KillIcons();
    KillSockets();
    KillDraw();
    KillAxes();
    KillSciences();
    KillControls();
    KillJohnFiles();
    KillFiles();
    if (TrashDayFlag)
    {
        TrashDay();
    }

    KillLists();
    KillArrays();
    KillObjects();
    KillNames();
    exit(0);
}

InitStuff()
/*Initializes stuff.  Has to be called after one window has been opened.*/
{
    if (!stuffInited)
    {
#ifdef GETGDESCAFTER
	GetConfiguration();
#endif
	InitDraw();
	InitIcons();
	InitSockets();
	InitColors();
	InitDrawings();
	InitSpaces();
	InitTimers();
	InitGeometry();
	InitDatasets();
	InitFilters();
	InitFiles();
	InitJohnFiles();
	InitPictures();
	InitFonts();
	InitWindows();
	InitObjWindows();
	InitObjFunctions();
	InitVisWindows();
	InitVisObjects();
	InitDialogs();
	InitPreferences();
	InitRecorders();
	InitGlobalFunctions();

	/*Set up cursors*/
#ifdef GRAPHICS
#ifdef CURSORS4D
#ifdef GL4D
	curstype(C16X1);
#endif
	defcursor(WATCHCURSOR, watchCursor);
	curorigin(WATCHCURSOR, 8, 8);
	defcursor(QUESTIONCURSOR, questionCursor);
	curorigin(QUESTIONCURSOR, 8, 8);
	defcursor(ICONCURSOR, iconCursor);
	curorigin(ICONCURSOR, 8, 8);
#endif
#endif
	stuffInited = true;
#ifdef SIGNALS
#ifdef SIGALRM
	signal(SIGALRM, SignalHandler);
	{
	    struct itimerval value, ovalue;
    
	    value . it_interval . tv_sec = 0;
	    value . it_interval . tv_usec = 0;
	    value . it_value . tv_sec = 0;
	    value . it_value . tv_usec = 100000L;
    
	    setitimer(ITIMER_REAL, &value, &ovalue);
	}
#endif
#endif
    }
}

