/*
 * (C) 1991 by Dirk Heckmann D-7750 Konstanz
 * all rights reserved - alle Rechte vorbehalten
 *
 * Dirk Heckmann
 * Sonnenbühlstr.56
 * D-7750 Konstanz
 *
 * Another AREXX interface for the XDME. Uses HRexx.c, some tools, I wrote
 * for a easier AREXX-usage.
 * This module implements the same commands as "rexx.c", so it works with
 * a minimum of changes in the real XDME sources.
 * Because I want to implement a, which is ALWAYS calleble from the outer
 * world (other tasks), I was forced to made some minor changes in main.c
 * (marked with "/ * HD " as comment ). Further I had to add an Activate
 * Window to cmd1.c's QUIT command , because it dosen't work proper if it
 * was called with a deactivated window.
 * In addition I added my new commands in the commandtable in "command.c"
 */
/*
 * Modification History
 * Date 	Modification					by
 * 26 Dec 1991	created 					Dirk Heckmann
 */

#include "defs.h"
#include "hrexx.h"
#include "rexx/storage.h"
#include "rexx/rxslib.h"
#include "rexx/rexxio.h"
#include "rexx/errors.h"

Prototype ULONG RexxMask;
Prototype int foundcmd; /* control for implicit ARexx macro invocation	 */
Prototype int cmderr;	/* global command error flag for do_rexx()'s use */

Prototype void	 openrexx	     (void);
Prototype void	 closerexx	     (void);
Prototype void	 do_rx		     (void);
Prototype void	 do_rx1 	     (void);
Prototype void	 do_rx2 	     (void);
Prototype long	 do_rxImplied	     (char *, char *);
Prototype void	 extern_rexx_command (void);
Prototype void	 to_port	     (void);
Prototype void	 select_window	     (void);
Prototype void	 project_info	     (void);
Prototype int	 load_project	     (void);
Prototype void	 save_project	     (void);
Prototype void	 put_rexx_result     (void);
Prototype char * get_rexx_result     (void);
Prototype long	 do_rexx	     (const char * port, const char *fmt, ...);

__stkargs static void in_rexx (struct RexxMsg *);


/************************************************************************/
/*			globale Variablentypen				*/
/************************************************************************/


/************************************************************************/
/*			  globale Variablen				*/
/************************************************************************/

ULONG RexxMask; 	/* ArexxPort signalmask for Wait		*/
int   foundcmd; 	/* control for implicit ARexx macro invocation	*/
int   cmderr;		/* global command error flag for do_rexx's use  */

static char rexx_result[256];	/* hier wird das Rexxresult untergerbracht */


/************************************************************************/
/*			   lokale  Funktionen				*/
/************************************************************************/

__stkargs static void in_rexx (struct RexxMsg *rmsg)
/*
 * this function is called with incomming Rexxmessages, while
 * processing SyncRexxCommand
 *
 * --> rmsg	pointer to the RexxMessage
 */
{
   long ret;
   foundcmd = 0;

   *rexx_result = 0;

   ret = !do_command ((char *)ARG0(rmsg));

   if (rexx_result[0])
      ReplyRexxMsg (rmsg, ret, rexx_result);
   else
      ReplyRexxMsg (rmsg, ret, 0);

   *rexx_result= 0;

   do_command ("null");     /* reset foundcommand */
}


/************************************************************************/
/*			   globale Funktionen				*/
/************************************************************************/

long do_rexx (const char * port, const char *fmt,...)
/*
 * This command transmittes the command, printf-style, to a named
 * port.
 *
 * --> port	name of port
 * --> fmt	printf-like format string for the command
 * --> ...	the args for the command
 */
{
    va_list va;
    char macro[256];

    va_start (va, fmt);
    vsprintf (macro, fmt, va);
    va_end (va);

    return (SyncRexxCommand (port, macro, rexx_result, sizeof(rexx_result), 0));
}


void put_rexx_result (void)
/*
    Copy a string to rexx_result
*/
{
    strcpy (rexx_result, av[1]);
}


char * get_rexx_result (void)
/*
    Get Contents of rexx_result
*/
{
    puts (rexx_result);

    return (rexx_result);
}


void openrexx (void)
/* initalizes the Arexx-stuff */
{
   int number;

   number = 1;

   Forbid ();

   do {
	sprintf (RexxPortName, "XDME.%d", number ++);
   } while (FindPort (RexxPortName) && number < 1000);

   Permit ();

   RexxMask = OpenRexx (RexxPortName, "XDME", in_rexx, 0, 0);

   if (!RexxMask)
	exiterr ("Cannot open AREXX-Port");
}


void closerexx (void)
/* shut down the Arexx-stuff */
{
   CloseRexx ();
}


void  do_rx (void)
/*
 *  explicit invocation interface between do_command() and do_rexx
 *  for ARexx macros having NO arguments (i.e., for the "rx" command)
 */
{
    do_rexx (0,"%s",av[1]);
}


void do_rx1 (void)
/*
 *  explicit invocation interface between do_command() and do_rexx
 *  for ARexx macros having ONE argument (i.e., for the "rx1" command)
 */
{
    do_rexx (0,"%s %s",av[1],av[2]);
}


void do_rx2 (void)
/*
 *  explicit invocation interface between do_command() and do_rexx
 *  for ARexx macros having TWO arguments (i.e., for the "rx2" command)
 */
{
    do_rexx (0,"%s %s %s",av[1],av[2],av[3]);
}


long do_rxImplied (char * cmd,char * args)
/*
 *  implicit invocation interface between do_command() and do_rexx
 *  for ARexx macros implicitly called; arbitrary number of arguments
 */
{
    return (do_rexx (0,"%s %s",cmd,args));
}

/***********************************************************************/
/***********		   New Commands 		   *************/
/***********************************************************************/

void extern_rexx_command (void)
/*
 * executes a command, comming in from an external port
 */
{
    long	     ret;
    struct RexxMsg * rmsg;

    *rexx_result = 0;

    rmsg = GetRexxMsg ();

    ret = !do_command ((char *)ARG0(rmsg));

    if (rexx_result[0])
	ReplyRexxMsg (rmsg, ret, rexx_result);
    else
	ReplyRexxMsg (rmsg, ret, 0);

    *rexx_result = 0;
} /* extern_rexx_command */


void to_port (void)
/*
 * simply passes a command to another named port
 */
{
    do_rexx (av[1], "%s", av[2]);
} /* to_port */


void select_window (void)
/*
 * selects another window FIRST LAST NEXT PREVIOUS WINDOW=<NAME> SAVE LOAD
 * every command can be abreviated by its first character:
 *  "select window=cmd1.c" = "select w=cmd1.c"
 */
{
    ED	      * ed     = NULL;
    static ED * sto_ed = NULL;

    switch (av[1][0]) {
	case ('l') : {
	    if (av[1][1] == 'a')
		ed = (ED *)GetTail (&DBase);
	    else
		ed = sto_ed;
	break; } /* case ('l') */

	case ('f') : {
	    ed = (ED *)GetHead (&DBase);
	break; } /* case ('f') */

	case ('n') : {
	    ed = GetPred (Ep);
	break; } /* case ('n') */

	case ('p') : {
	    ed = GetSucc (Ep);
	break; } /* case ('p') */

	case ('a') : {
	    ActivateWindow (Ep->Win);
	break; } /* case ('a') */

	case ('s') : {
	    sto_ed = Ep;
	break; } /* case ('s') */

	case ('w') : {
	    char * ptr;

	    ptr = av[1];

	    while (*ptr && *ptr != '=')
		ptr ++;

	    if (*ptr)
		ptr ++;
	    else
		break;

	    ed = (ED *)GetHead(&DBase);    /* ed = first window */

	    while (ed) {                   /* search window with name av[1] */
		if (!stricmp (ed->Name, ptr))   /* found it */
		    break;

		ed = GetSucc (ed);              /* examine next */
	    }
	break; } /* case ('w') */

    } /* switch (av[1][0]) */

    if (ed) {
	text_switch (ed->Win);

	ActivateWindow (ed->Win);
    } else {
	Abortcommand = 1;
    }
} /* select_window */


void project_info (void)
/*
 * builds the following string:
 * path <name> <left> <top> <width> <height> <iconleft> <iconright>
 * if Rexx called this string is return as resultstring
 */
{
    char path[PATHSIZE];		/* Puffer für Pfad */

    getpathto (Ep->dirlock, "", path);

    /* Read values from Window-Struct */
    if (Ep->iconmode) {
	Ep->IWinx     = Ep->Win->LeftEdge;
	Ep->IWiny     = Ep->Win->TopEdge;
    } else {
	Ep->Winx      = Ep->Win->LeftEdge;
	Ep->Winy      = Ep->Win->TopEdge;
	Ep->Winwidth  = Ep->Win->Width;
	Ep->Winheight = Ep->Win->Height;
    }

    sprintf (rexx_result, "\"%s\" \"%s\" %d %d %d %d %d %d %d",
			   path,    Ep->Name,
					 Ep->Winx,
					    Ep->Winy,
					       Ep->Winwidth,
						  Ep->Winheight,
						     Ep->IWinx,
							Ep->IWiny,
							   Ep->Line
    );
} /* project_info */


void save_project (void)
/*
 * saves all opened files in the directory of the currently active
 * editor to a file name "XDME_Project_File".
 * The lines are in the same format as returned from project_info
 */
{
    ED * ed;				/* Currenteditor */
    ED * act_ed;			/* active Editor */
    BPTR old_lock;			/* Active dirlock */
    BPTR file;				/* our PRJ file */

    old_lock = CurrentDir (Ep->dirlock); /* change dir */
    act_ed   = Ep;			 /* save active Editor */

    file = Open ("XDME_Project_File", MODE_NEWFILE);

    if (file) {
	Write (file, "# path name x y w h ix iy line\n", 31L);

	for (ed=(ED *)GetHead(&DBase); ed; ed=(ED *)GetSucc((struct Node *)ed)) {
	    Ep = ed;			 /* change current ed */

	    project_info ();             /* build info text */

	    Write (file, rexx_result, strlen (rexx_result));
	    Write (file, "\n", 1L);
	}

	Close (file);
    } /* if (file) */

    Ep = act_ed;			 /* restore actuall editor */

    CurrentDir (old_lock);               /* go back to old dir */
} /* project_save */


int load_project (void)
{
    FILE * file;
    char   path[PATHSIZE];		/* Puffer für Pfad */
    char   name[60];			/* file name */
    char * ptr;
    long   t, il, it, line;		/* window & icon & line */

    file = fopen ("XDME_Project_File", "r");  /* Open ProjectFile */

    if (file) {
	while (fgets (tmp_buffer, 256, file)) {
	    if (*tmp_buffer == '#')
		continue;

	    ptr = skip_whitespace (tmp_buffer);

	    if (*ptr == '"') {
		ptr ++;

		for (t=0; *ptr != '"'; )
		    path[t ++] = *ptr ++;

		ptr ++;
	    } else
		for (t=0; !isspace(*ptr); )
		    path[t ++] = *ptr ++;

	    path[t] = 0;
	    ptr = skip_whitespace (ptr);

	    if (*ptr == '"') {
		ptr ++;

		for (t=0; *ptr != '"'; )
		    name[t ++] = *ptr ++;

		ptr ++;
	    } else
		for (t=0; !isspace(*ptr); )
		    name[t ++] = *ptr ++;

	    name[t] = 0;

	    av[1] = ptr;
	    do_openwindow ();

	    av[1] = path;
	    do_cd ();

	    av[0] = "newfile";
	    av[1] = name;
	    do_edit ();

	    sscanf (ptr, " %d  %d  %d  %d  %d   %d   %d\n",
			   &t, &t, &t, &t, &il, &it, &line);

	    if (line >= Ep->Lines)
		line = Ep->Lines - 1;

	    Ep->Line = line;

	    text_load ();
	    text_sync ();

	    Ep->IWinx = il;
	    Ep->IWiny = it;

	    do_iconify ();
	}

	fclose (file);

	t = TRUE;
    } else
	t = FALSE;

    return (t);
} /* load_project */


