/* 
 * tkAppInit.c --
 *
 *	Provides a default version of the Tcl_AppInit procedure for
 *	use in wish and similar Tk-based applications.
 *
 * Copyright (c) 1993 The Regents of the University of California.
 * Copyright (c) 1994 Sun Microsystems, Inc.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 */
/******************************************************************************
 * This code release was developed and written by 
 * Joe Macker and Winston Dang,
 * 1996, 1997
 ******************************************************************************/

#ifndef lint
static char sccsid[] = "@(#) tkAppInit.c 1.15 95/06/28 13:14:28";
#endif /* not lint */

#include "tk.h"

/* INSERTED FOR SATELLITE PROGRAMMING */
#include <stdio.h>
#include <signal.h>
#include <string.h>

#define TRUE 1
#define FALSE 0
#define IDLEPOLL_TIME 15    
char DEFAULT_PORT[] = "37793";
char DEFAULT_HOST[] = "224.2.158.99";
#define BUF_TYPE_ID   0       /* file identification packet */
#define BUF_TYPE_NEW_MEM 5  
#define BUF_TYPE_MISS_REQ 6   /* missing packet request */
#define BUF_TYPE_MISS_ANS 7


#define POLL_INTERVAL 100

/* IMM SPECIFIC OPTIONS */

/**************** IMM SPECIFIC OPTIONS ****************************/
char *name = NULL;
char *portnum = NULL;
char *hostname = NULL;
char *title;
char *timetolive = NULL;
char *archfile = NULL;
char *imm2xv = NULL;
char *logname = NULL;
char *userstring = NULL;
extern int debug;
extern u_char ttl;
extern char *immdirectory;
int archfilenum = 2;
int serverid = 0;
int locktransmit = 0;
char *useimageloader = NULL;
char *localhost = NULL;

extern int debug;

extern char *immdirectory;
extern int archfilenum;
extern int serverid;
extern char *useimageloader;
extern char *localhost;
char *myhostname;

extern int debug;
extern SIG_T abortimage();
extern int newmember();
extern int checkpath();
extern int xlredraw();
extern int closeall();
extern int chghostname();
extern FILE *logfp;
extern char *OpenRecvFD();
extern int err_in_block;

/* TK script declarations */
extern char IMM_Init[];
extern char MCL[];
extern char RADIO[];
extern char LISTBOX[];
extern char VIEWBOX[];
extern char FILEBOX[];
extern char HOSTBOX[];
extern char SERVERBOX[];

Tcl_Interp *interpeter;

Tk_TimerToken  timer_token;
/*
 * The following variable is a special hack that is needed in order for
 * Sun shared libraries to be used for Tcl.
 */

extern int matherr();
void GetDspStatus();
int *tclDummyMathPtr = (int *) matherr;

/***************************************************************************/
/* fork and initiate server process */
static int exec_server(clientdata, interp, argc, argv)
ClientData clientdata;
Tcl_Interp *interp;
int argc;
char *argv[];
{
    int transmitflag = FALSE;
    int ofp;
    char timetolive[3];
    char portnumber[10];
    char repeatnum[4];

    if (argc != 15) {
	Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
			 " filename\"", NULL);
	return TCL_ERROR;
    }

    sprintf(timetolive,"%d",ttl);
    sprintf(portnumber,"%s",portnum);
#ifdef SIGCLD	
	signal(SIGCLD,SIG_IGN);
#endif
#ifdef SIGCHLD
	signal(SIGCHLD,SIG_IGN);
#endif
    serverid = fork();
    switch(serverid) {
    case -1:
	perror(argv[0]);
	fprintf(stderr, "%s: unable to fork \n",argv[0]);
	exit(1);
    case 0:	/* Child process */
	if (debug) fprintf( stderr,
			   "immserv -p %s -i %s -t %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s\n",
			   portnumber,hostname, timetolive,
			   argv[1],argv[2],argv[3],argv[4],argv[5],
		           argv[6],argv[7],argv[8],argv[9],argv[10],
		           argv[11],argv[12],argv[13],argv[14]);
	fclose(stdin);
	closeall();

	Tcl_DeleteInterp(interp);
	if (localhost == NULL)
	    execlp("immserv","immserv","-p",portnumber,
		   "-i",hostname,"-t",timetolive,
		   argv[1],argv[2],argv[3],argv[4],argv[5],
		   argv[6],argv[7],argv[8],argv[9],argv[10],
		   argv[11],argv[12],argv[13],argv[14],
		   NULL);
	else
	    execlp("immserv","immserv","-p",portnumber,
		   "-L",localhost,
		   "-i",hostname,"-t",timetolive,
		   argv[1],argv[2],argv[3],argv[4],argv[5],
		   argv[6],argv[7],argv[8],argv[9],argv[10],
		   argv[11],argv[12],argv[13],argv[14], 
		   NULL);
	fprintf(stderr, "unable to exec immserv\n");
	exit(0);
    default:
	return TCL_OK;
    }
}
/***************************************************************************/
/* change the name of the host */
static int ChgVarHost(clientdata, interp, argc, argv)
ClientData clientdata;
Tcl_Interp *interp;
int argc;
int *argv[];
{
    char *myhostname;
    if (argc != 2) {
	Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
			 " filename\"", NULL);
	return TCL_ERROR;
    }
    chghostname(argv[1]);
    return TCL_OK;

}
/***************************************************************************/
/* set debug flag */
/*ARGSUSED*/
static int DebugProc(clientdata, interp, argc, argv)
ClientData clientdata;
Tcl_Interp *interp;
int argc;
int *argv[];
{
    debug = !debug;
    return TCL_OK;
}
/***************************************************************************/
/* return time of day  in seconds for timer */
/*ARGSUSED*/
static int TimeOfDay(clientdata, interp, argc, argv)
ClientData clientdata;
Tcl_Interp *interp;
int argc;
int *argv[];
{
    sprintf(interp->result,"%u", time(NULL));
    return TCL_OK;
}
/**************************************************************************/
/*ARGSUSED*/
static int ShutdownCmd(clientdata, interp, argc, argv)
ClientData clientdata;
Tcl_Interp *interp;
int argc;
int *argv[];

{
    Tcl_DeleteInterp(interp);
    abortimage();
    exit(0);
}

/**************************************************************************/
/* redraw the image */
/*ARGSUSED*/
static int RedrawCmd(clientdata, interp, argc, argv)
ClientData clientdata;
Tcl_Interp *interp;
int argc;
int *argv[];
{
    int i;
    i = xlredraw();
    if (i)
	Tcl_GlobalEval(interp,".frame.l1 config -text \"View Image\"");
    else
	Tcl_GlobalEval(interp,".frame.l1 config -text \"Queue empty\"");
    return TCL_OK;
}



/* read the configuration file */
int initialize(argc, argv)
int argc;
char *argv[];
{
    int i=1;
    while (i < argc) {
        if (*argv[i] == '-') {
            switch (*(argv[i] + 1)) {
            case 'N':
		i++;
		userstring = argv[i];
                break;
            case 'p':
                i++;
		portnum = argv[i];
		break;
	    case 'i':
		i++;
		hostname = argv[i];
		break;
	    case 'b':
		i++;
                debug = atoi(argv[i]);
                break;
#ifdef ERROR_TEST
            case 'e':
                /* set number of simulated dropped packets */
                i++;
                err_in_block = atoi (argv[i]);
                break;
#endif
	    case 'l':
		i++;
		logname = argv[i];
		break;
	    case 'L':
		i++;
		localhost = argv[i];
		break;
	    case 't':
		i++;
		timetolive = argv[i];
		break;
	    case 'a':
		i++;
		archfile = argv[i];
		break;
 	    }
	    i++;
	}
    }
}

/*
 *----------------------------------------------------------------------
 *
 * main --
 *
 *	This is the main program for the application.
 *
 * Results:
 *	None: Tk_Main never returns here, so this procedure never
 *	returns either.
 *
 * Side effects:
 *	Whatever the application does.
 *
 *----------------------------------------------------------------------
 */

int
main(argc, argv)
    int argc;			/* Number of command-line arguments. */
    char **argv;		/* Values of command-line arguments. */
{
    initialize(argc,argv);
    
    Tk_Main(argc, argv, Tcl_AppInit);
    abortimage();
    return 0;			/* Needed only to prevent compiler warning. */
}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_AppInit --
 *
 *	This procedure performs application-specific initialization.
 *	Most applications, especially those that incorporate additional
 *	packages, will have their own version of this procedure.
 *
 * Results:
 *	Returns a standard Tcl completion code, and leaves an error
 *	message in interp->result if an error occurs.
 *
 * Side effects:
 *	Depends on the startup script.
 *
 *----------------------------------------------------------------------
 */

int
Tcl_AppInit(interp)
    Tcl_Interp *interp;		/* Interpreter for application. */
{
    int result;
    Tk_Window main;

    interpeter = interp;
    
    if (Tcl_Init(interp) == TCL_ERROR) {
	return TCL_ERROR;
    }

    if (Tk_Init(interp) == TCL_ERROR) {
	return TCL_ERROR;
    }

#ifdef TK_TEST
    if (TkTest_Init(interp) == TCL_ERROR) {
	return TCL_ERROR;
    }
#endif
    
    /*
     * Call the init procedures for included packages.  Each call should
     * look like this:
     *
     * if (Mod_Init(interp) == TCL_ERROR) {
     *     return TCL_ERROR;
     * }
     * 
     * where "Mod" is the name of the module.
     */


    if (debug) printf("parsing args\n");
    if (name == NULL) {
        title = "IMM";
    } else {
        title = (char *)malloc((strlen(name) + 5));
        sprintf(title,"IMM %s",name);
    }
    if ((portnum == NULL) || (hostname == NULL)) {
        portnum = DEFAULT_PORT;
        hostname = DEFAULT_HOST;
    }
    if (timetolive != NULL)
        ttl = atoi(timetolive);
    if (archfile != NULL)
        archfilenum = atoi(archfile);
 
    chghostname(userstring);
 
    /* define the log file */ 
    logfp = stdout;
    if (logname != NULL) {
        logfp = fopen(logname,"w");
        if (debug) printf("log file %s\n",logname);
    }

    /*
     * Call Tcl_CreateCommand for application-specific commands, if
     * they weren't already created by the init procedures called above.
     */
    if (debug) printf("init Receiver\n");
    myhostname = OpenRecvFD(portnum,hostname,archfilenum);
    if (debug) printf("init TK\n");    
    Tcl_CreateCommand(interp,"immserv", (Tcl_CmdProc *)exec_server, 0, NULL);
    Tcl_CreateCommand(interp,"timeofday",(Tcl_CmdProc *)TimeOfDay, 0, NULL);
    Tcl_CreateCommand(interp,"debug_proc",(Tcl_CmdProc *)DebugProc, 0, NULL);
    Tcl_CreateCommand(interp,"shutdown",(Tcl_CmdProc *)ShutdownCmd, 0, NULL);
    Tcl_CreateCommand(interp,"chgvarhost",(Tcl_CmdProc *)ChgVarHost, 0, NULL);    
    Tcl_CreateCommand(interp,"redraw",(Tcl_CmdProc *)RedrawCmd, 0, NULL);

    /*
     * Specify a user-specific startup file to invoke if the application
     * is run interactively.  Typically the startup file is "~/.apprc"
     * where "app" is the name of the application.  If this line is deleted
     * then no user-specific startup file will be run under any conditions.
     */
   /* Execute initialization script */
    result = Tcl_VarEval(interp,IMM_Init,MCL,RADIO,
                         LISTBOX, VIEWBOX, FILEBOX, HOSTBOX, SERVERBOX, NULL);
    if (result != TCL_OK) return result;

    (void) Tcl_Eval(interp, "update");
    /* Tk_CreateTimerHandler(IDLEPOLL_TIME * 1000, CheckIdle, NULL); */
 
    /* set up a few defaults settings */
    Tcl_SetVar(interp,"hostname", myhostname,0);
    Tcl_SetVar(interp,"immdirectory", immdirectory,0);
    Tcl_SetVar(interp,"PORT", portnum,0);
    Tcl_SetVar(interp,"ADDRESS", hostname,0);
    if (imm2xv != NULL) Tcl_SetVar(interp,"opt_size", "10",0);
    newmember(10);

    fflush(stdout);
 
    /*
     * Loop infinitely, waiting for commands to execute.  When there
     * are no windows left, Tk_MainLoop returns and we exit.
     */
 
    Tk_MainLoop();
 
    /*
     * Don't exit directly, but rather invoke the Tcl "exit" command.
     * This gives the application the opportunity to redefine "exit"
     * to do additional cleanup.
     */
 
    Tcl_Eval(interp, "exit");
    exit(1);
 
    
/*    return TCL_OK; */
}

/******************************************************************************/
/* move the scale slider */
int scaleset(position)
int position;
{
    char cmd[256];
    static int lastpos = 0;
    if (lastpos != position) {
	sprintf(cmd,"setWidth .frame.canvas %d",position);
	(void)Tcl_Eval(interpeter, cmd);
	lastpos = position;
    }
    if (locktransmit) return;
    locktransmit = 300;
    buttset(BUF_TYPE_NEW_MEM,cmd,NULL);
}
/******************************************************************************/
/* move the scale slider */
int memberadd(user,ipaddress,good,bad,retries,packets)
char *user;
char *ipaddress;
unsigned short good;
unsigned short bad;
unsigned short retries;
unsigned short packets;
{
    char cmd[512];
    sprintf(cmd,"memberadd %u %u %u %u {%s} {%s}", 
	    good,bad,retries,packets,user,ipaddress);
    (void)Tcl_VarEval(interpeter, cmd, NULL);
}
/******************************************************************************/
/* move the scale slider */
int serveradd(user,filename)
char *user;
char *filename;
{
    char cmd[256];
    char *ipaddress;
    ipaddress = strchr(user,'@');
    ipaddress++;
    sprintf(cmd,"serveradd %s %s %s", ipaddress,user,filename);
    (void)Tcl_VarEval(interpeter, cmd, NULL);
}

/******************************************************************************/
/* set the button text in the main window */
int buttset(opt,desc, receiver)
int opt;
char *desc;
char *receiver;
{
    char cmd[256];
    int i;
    static char connected = FALSE;
    switch (opt) {	
    case BUF_TYPE_ID:
	Tcl_GlobalEval(interpeter,"set timedurat 0");
	sprintf(cmd,".frame.l1 config -text \"%s\"",receiver);
	(void)Tcl_VarEval(interpeter, cmd, NULL);
	sprintf(cmd,".ok config -text \"%s\"",desc);
	connected = TRUE;
	break;
    case BUF_TYPE_NEW_MEM:
	if (connected) return;
	sprintf(cmd,".ok config -text \"Connect %s\"",hostname);
	break;
    case BUF_TYPE_MISS_ANS:
	Tcl_SetVar(interpeter,"timedurat",desc,0);
	sprintf(cmd,"blink");
	break;
    case BUF_TYPE_MISS_REQ:
	Tcl_SetVar(interpeter,"timedurat",desc,0);
	i = atoi(desc);
	if ( i > 0) locktransmit = i;
	scaleset(0);
	sprintf(cmd,"blink");
	break;
	
    default:
	sprintf(cmd,".ok config -text \"%s\"",desc);
    }
    (void)Tcl_VarEval(interpeter, cmd, NULL);
}

/******************************************************************************/
/* build the xv options in the system call */
int build_xvopts(viewtype,line)
int viewtype;
char *line;
{
    char *size;
    char *normal;
    char *smooth;
    char *postProcFile;
    int retflag = FALSE;
    char *noreset;
    static int imm2xvflag = 0;
    *line = NULL;
    size = Tcl_GetVar(interpeter,"opt_size",0);
    /* test for custom setting in radio button */
    switch (atoi(size)) {
    case 10:
	switch (imm2xvflag) {
	case 0:
	    imm2xvflag = checkpath("imm2xv") + 1;
	    if (imm2xvflag != 1) break;
	case 1:
	    sprintf(line,"xv -wait %d ",locktransmit);
	    return 10;
	}
	if (imm2xv == NULL)
	    sprintf(line,"imm2xv -wait %d ",locktransmit);
	else
	    sprintf(line,"%s -wait %d ",imm2xv,locktransmit);
	return 10;
    case 11:
	return 11;
    case 12:
	postProcFile = Tcl_GetVar(interpeter,"postProcFile",0);
	strcpy(line,postProcFile);
	return 12;
    default:
	retflag = TRUE;
	switch (viewtype) {
	case 1:
	    sprintf(line,"-rmode %s",size);
	    if (*size == '5') strcat(line," -maxp");
	    break;
	default:
	    if (*size == '5') strcpy(line," -full");
	}
	
    case -1:
	normal = Tcl_GetVar(interpeter,"opt_dither",0);
	if (*normal == '1') {
	    switch (viewtype) {
	    case 1:
		strcat(line," -dither");
		break;
	    default:
		strcat(line,"  -colord");
	    }
	    retflag = TRUE;
	}
	smooth = Tcl_GetVar(interpeter,"opt_smooth",0);
	if (*smooth == '1') {
	    retflag = TRUE;
	    strcat(line," -smooth");
	}
	noreset = Tcl_GetVar(interpeter,"opt_noreset",0);
	if (*noreset == '1') {
	    retflag = TRUE;
	    strcat(line, " -nore");
	}
	return retflag;
    }
    
}








