/*(( "Kopf" */
/* -----------------------------------------------------------------------------

   $Id: dispatcher.c,v 1.4 1997/06/26 14:34:53 mshopf Exp mshopf $

   GoldED API client, ©1997 Matthias Hopf.
   Compiled with SasC.


   Function dispatcher.

   ------------------------------------------------------------------------------
*/

/*)) */
/*(( "Includes" */

#include "smartindent.h"
#include "dispatcher.h"
#include "util.h"

#include <proto/dos.h>
#include <proto/intuition.h>

#include <exec/types.h>
#include <dos/dos.h>
#include <intuition/intuition.h>

#include <string.h>

/*)) */

/*(( "Template" */

static char *MainTemplate = "MODE/K,DEBUG/N/K,CONFIG/M/N/K";

/*)) */

/********** Private **********/
/*(( "DoIndentation ()" */

static char *DoIndentation (sc_t *c, int BeginLine, int EndLine, int Mode)
{
    InitIndent (c, BeginLine, EndLine, Mode);
    (*c->Sem->Indent) (c);

    CleanupIndent (c);
    return (c->ErrTxt);
}


/*)) */
/*(( "Cmd_SmartIndent ()" */

static char *Cmd_SmartIndent (sc_t *c, struct APIMessage *msg, LONG *args)
{
    int                Mode      = 0;
    int Start, End;
    struct EditConfig *Edit = c->Edit;

    Start = Edit->Line;
    End   = Edit->Line - 1;

    if (args[0])
    {
	Mode |= MODE_LINE;
	End   = Edit->Line;
    }
    if (args[1])
    {
	Mode |= MODE_LASTLINE;
	Start = Edit->Line - 1;
    }
    if (args[2])
    {
	Mode |= MODE_CURSOR;
    }
    if (args[3])
    {
	Mode |= MODE_BLOCK;
	Start = Edit->BlockStartY;
	End   = Edit->BlockEndY;
	if (Edit->Marker == BLOCKMODE_NONE)
	    return ("No block specified");
    }

    if (Mode == 0)
	return ("No mode specified");

    return (DoIndentation (c, Start, End, Mode));
}


/*)) */

/********** Public **********/
/*(( "ScanArgs ()" */

/* Scan startup arguments, return Mode, when sucessfull */

char *ScanArgs (sc_t *c, char *cmd, struct APIMessage *msg)
{
    struct RDArgs *rdArgs, *args;
    const char    *Mode = NULL, *Error = NULL;

    if ( (rdArgs = AllocDosObject(DOS_RDARGS, NULL)) )
    {
	char  Buffer [80 +1];
	LONG  argArray[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
	short *cp;
	long  **p;
	struct Semantic **s;

	    /* make LF-terminated copy of command string (required by dos/readArgs): */

	strncpy (Buffer, cmd, sizeof (Buffer)-2);
	strcat  (Buffer, "\12");

	rdArgs->RDA_Source.CS_Buffer = Buffer;
	rdArgs->RDA_Source.CS_Length = strlen (Buffer);

	if ( (args = ReadArgs (MainTemplate, argArray, rdArgs)) )
	{
	    if (argArray [0])
	    {
		Mode = ((char **) argArray) [0];
		for (s = Semantics; *s; s++)
		{
		    if (strcasecmp (Mode, (*s)->Name) == 0)
			c->Sem = *s;
		}
		if (! c->Sem)
		    Error = UNKNOWN_MODE_ERROR;
	    }
	    else
		Error = UNSPECIFIED_MODE_ERROR;
		/* TODO: dynamic type detection when MODE/K is not given */

#ifdef DEBUG
	    if (argArray [1])
		Dbug = * ((long **) argArray) [1];
#endif
		/* create configuration */
	    memcpy (&(c->Conf), &(c->Sem->StartConf), sizeof (struct SmartConfig));
	    if (argArray [2])
	    {
		p  = ((long ***) argArray) [2];
		for (cp = (short *) &(c->Conf); cp < (short *) (&(c->Conf) + 1); cp++)
		    if (*p)
			*cp = **p++;
		    else
			break;
	    }

	    FreeArgs(args);
	}
	else
	{
	    Fault (IoErr(), MainTemplate, Buffer, sizeof (Buffer)-1);
	    Error = Buffer;
	}

	FreeDosObject(DOS_RDARGS, rdArgs);
    }
    else
	Error = "AllocDosObject() failed";

    if (Error)                          /* an error occured */
    {
	struct EasyStruct es = { sizeof (struct EasyStruct), NULL, "Smartindent error", NULL, "Ok" };

	es.es_TextFormat = (char *) Error;
	EasyRequest (NULL, &es, NULL, NULL);
	return NULL;
    }

    return Mode;
}


/*)) */
/*(( "DispatchKey ()" */

void DispatchKey (sc_t *c, struct APIMessage *msg)
{
#ifdef DEBUG
    char k [2];
    extern Dbug_Counter;
    Dbug_Counter = 0;
    k [0] = (int) msg->api_Data;
    k [1] = 0;
    debug (D_KEY, ("Keycode 0x%lx, '%s'\n", (long) msg->api_Data, k));
#endif

    c->Edit = (struct EditConfig *) msg->api_Instance->api_Environment;
    c->Msg  = msg;

    (*c->Sem->KeyPress) (c, (int) msg->api_Data);

    msg->api_RC = RC_OK;
    if ( (msg->api_CommandError = c->ErrTxt) )
	msg->api_RC = RC_WARN;
}


/*)) */
/*(( "DispatchCmd ()" */

void DispatchCmd (sc_t *client, struct APIMessage *msg)
{
    struct RDArgs *rdArgs, *args;

#ifdef DEBUG
    extern Dbug_Counter;
    Dbug_Counter = 0;
#endif

    client->Edit = (struct EditConfig *) msg->api_Instance->api_Environment;
    client->Msg  = msg;

    if ( (rdArgs = AllocDosObject(DOS_RDARGS, NULL)) )
    {
	ULONG n;
	char  buffer [80];
	LONG argArray[] = { 0, 0, 0, 0, 0, 0, 0, 0 };

	    // make LF-terminated copy of command string (required by dos/readArgs):

	strncpy (buffer, msg->api_Command, sizeof(buffer));
	strcat  (buffer, "\12");

	for (n = 0; Parser[n].Cmd; n++)
	{
	    if (memcmp(buffer, Parser[n].Cmd, strlen(Parser[n].Cmd)) == 0)
	    {
		UBYTE *arguments = buffer + strlen(Parser[n].Cmd);

		    // tell host that message has been consumed by us:

		msg->api_State = API_STATE_CONSUMED;
		msg->api_RC    = RC_OK;

		rdArgs->RDA_Source.CS_Buffer = arguments;
		rdArgs->RDA_Source.CS_Length = strlen(arguments);
		rdArgs->RDA_Source.CS_CurChr = 0;
		rdArgs->RDA_DAList           = NULL;
		rdArgs->RDA_Buffer           = NULL;

		if (Parser[n].Template)
		{
		    if ( (args = ReadArgs(Parser[n].Template, argArray, rdArgs)) )
		    {
			if ( (msg->api_CommandError = (*Parser[n].Handler)(client, msg, argArray)) )
			    msg->api_RC = RC_WARN;
			FreeArgs(args);
		    }
		    else {
			static UBYTE errorText[80 + 1];
			msg->api_RC           = RC_WARN;
			msg->api_CommandError = errorText;
			Fault(IoErr(), "IoErr()", errorText, 80);
		    }
		}
		else
		{
		    if ( (msg->api_CommandError = (*Parser[n].Handler)(client, msg, argArray)) )
			msg->api_RC = RC_WARN;
		}

		break;
	    }
	}

	FreeDosObject(DOS_RDARGS, rdArgs);
    }
}


/*)) */

/*(( "Dispatchlists" */

char *apiCommands[] = { "SMARTINDENT LINE/S,LASTLINE/S,CURSOR/S,BLOCK/S", NULL };

struct Parser Parser[] =
{
	/*
	 * SMARTINDENT:
	 *     LINE:     indent current line
	 *     LASTLINE: indent line above cursor
	 *     CURSOR:   Set Cursorpos to indentation position
	 *     BLOCK:    indent marked block
	 */
    "SMARTINDENT", Cmd_SmartIndent, "LINE/S,LASTLINE/S,CURSOR/S,BLOCK/S",

    NULL
} ;

/*)) */

