#define __USE_SYSBASE

#include <exec/types.h>
#include <exec/execbase.h>
#include <dos/rdargs.h>
#include <dos/dosextens.h>
#include <dos/var.h>
#include <devices/trackdisk.h>
#include <support/types.h>
#include <support/exec.h>

#include <string.h>

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

#include "clickstart.rev.h"

#define DOS_NAME		"dos.library"
#define DOS_VERN		37L
#define TRACK_NAME	"trackdisk.device"

#define TEMPLATE		"CLICK/S,NOCLICK/S,STAR/S,NOSTAR/S,PIPE/K,NOPIPE/S,"\
										"MULTI/K,NOMULTI/S,ALERT/K/N,QUIET/S"

#define OPT_CLICK		0
#define OPT_NOCLICK	1
#define OPT_STAR		2
#define OPT_NOSTAR	3
#define OPT_PIPE		4
#define OPT_NOPIPE	5
#define OPT_MULTI		6
#define OPT_NOMULTI	7
#define OPT_ALERT		8
#define OPT_QUIET		9
#define OPT_COUNT		10

#define STATE_CLICK	0
#define STATE_STAR	1
#define STATE_PIPE	2
#define STATE_MULTI	3
#define STATE_ALERT	4
#define STATE_COUNT	5

/* Pipe enable/disable */
#define PIPE_VAR_NAME		"_pchar"
#define PIPE_VAR_LEN		1
#define PIPE_VAR_FLAGS	(LV_VAR | GVF_LOCAL_ONLY)

/* Multi command enable/disable */
#define MULT_VAR_NAME		"_mchar"
#define MULT_VAR_LEN		1
#define MULT_VAR_FLAGS	(LV_VAR | GVF_LOCAL_ONLY)

#define VAR_PIPE				0
#define VAR_MULTI				1
#define VAR_COUNT				2
#define VAR_SIZE				max(PIPE_VAR_LEN,MULT_VAR_LEN)+3

/* Default pipe and multi characters */
#define DEF_PIPE				"|"
#define DEF_MULTI				"\\"

#define ONOFF(flag) 		((flag) ? "ON" : "OFF")
#define PStr(arg,def)		(*((STRPTR)(arg))=='\0' ? (STRPTR)(def) : (STRPTR)(arg))
#define AlTime(time)		((time)>0 ? (time) : 0)

STATIC CONST TEXT VersionString[]=
	VERSION(PROG_NAME,PROG_VERSION,PROG_REVISION,PROG_DATE);

ULONG ClickStart(VOID)
{
	struct ExecBase *SysBase=*((struct ExecBase **)4);
	struct DosLibrary *DOSBase;

	struct RDArgs *Args;
	struct MsgPort *Port;
	struct IOExtTD *IO;
	struct LocalVar *Var;
	LONG Options[OPT_COUNT];
	ULONG Unit,RC=RETURN_FAIL;
	STRPTR States[STATE_COUNT];
	CHAR VarValues[VAR_COUNT][VAR_SIZE];
	BOOL ErrOccured=FALSE;

	if(!(DOSBase=(struct DosLibrary *)OpenLibrary(DOS_NAME,DOS_VERN)))
	{
		SetResult2(ERROR_INVALID_RESIDENT_LIBRARY);
		goto InvalidDOS;
	}

	clear(&Options);										/* Clear out buffer */
	if(!(Args=ReadArgs(TEMPLATE,Options,NULL)))
	{
		PrintFault(IoErr(),NULL);					/* Inform user */
		goto NoArgs;
	}

	States[STATE_CLICK]="?";		/* In case it is not possible to open device */

	if(Port=CreateMsgPort())
	{
		if(IO=CreateIORequest(Port,sizeof(struct IOExtTD)))
		{
			for(Unit=0; Unit<4; Unit++)
			{
				if(OpenDevice(TRACK_NAME,Unit,(struct IORequest *)IO,0)==0)
				{
					if(Options[OPT_CLICK])
						fclr(((struct TDU_PublicUnit*)(IO->iotd_Req.io_Unit))->
									tdu_PubFlags,TDPF_NOCLICK);
					if(Options[OPT_NOCLICK])
						fset(((struct TDU_PublicUnit*)(IO->iotd_Req.io_Unit))->
									tdu_PubFlags,TDPF_NOCLICK);
					States[STATE_CLICK]=
						ONOFF(!ftst(((struct TDU_PublicUnit*)(IO->iotd_Req.io_Unit))->
												tdu_PubFlags,TDPF_NOCLICK));
					CloseDevice((struct IORequest *)IO);
				}
			}
			DeleteIORequest(IO);
		}
		else
			ErrOccured=TRUE;
		DeleteMsgPort(Port);
	}
	else
		ErrOccured=TRUE;

	/* Wildstar */
	if(Options[OPT_STAR])														/* Enable */
		fset(DOSBase->dl_Root->rn_Flags,RNF_WILDSTAR);
	if(Options[OPT_NOSTAR])													/* Disable */
		fclr(DOSBase->dl_Root->rn_Flags,RNF_WILDSTAR);
	States[STATE_STAR]=															/* Get current state */
		ONOFF(ftst(DOSBase->dl_Root->rn_Flags,RNF_WILDSTAR));

	/* Piping */
	if(Options[OPT_PIPE])														/* Enable pipes */
		ErrOccured=SetVar(PIPE_VAR_NAME,PStr(Options[OPT_PIPE],DEF_PIPE),
											PIPE_VAR_LEN,PIPE_VAR_FLAGS);
	if(Options[OPT_NOPIPE])													/* Disable pipes */
		ErrOccured=DeleteVar(PIPE_VAR_NAME,PIPE_VAR_FLAGS);
	if(Var=FindVar(PIPE_VAR_NAME,PIPE_VAR_FLAGS))		/* Check current state */
	{
		VarValues[VAR_PIPE][0]='\'';
		VarValues[VAR_PIPE][1]=*(Var->lv_Value);
		VarValues[VAR_PIPE][2]='\'';
		VarValues[VAR_PIPE][3]='\0';
		States[STATE_PIPE]=&VarValues[VAR_PIPE][0];
	}
	else
		States[STATE_PIPE]="OFF";

	/* Multi command execution */
	if(Options[OPT_MULTI])													/* Enable */
		ErrOccured=SetVar(MULT_VAR_NAME,PStr(Options[OPT_MULTI],DEF_MULTI),
											MULT_VAR_LEN,MULT_VAR_FLAGS);
	if(Options[OPT_NOMULTI])												/* Disable */
		ErrOccured=DeleteVar(MULT_VAR_NAME,MULT_VAR_FLAGS);
	if(Var=FindVar(MULT_VAR_NAME,MULT_VAR_FLAGS))		/* Check current state */
	{
		VarValues[VAR_MULTI][0]='\'';
		VarValues[VAR_MULTI][1]=*(Var->lv_Value);
		VarValues[VAR_MULTI][2]='\'';
		VarValues[VAR_MULTI][3]='\0';
		States[STATE_MULTI]=&VarValues[VAR_MULTI][0];
	}
	else
		States[STATE_MULTI]="OFF";

	/* Alerts timing */
	if(Options[OPT_ALERT])
		SysBase->LastAlert[3]=AlTime(*((LONG *)Options[OPT_ALERT]));
	States[STATE_ALERT]=(STRPTR)SysBase->LastAlert[3];

	RC=(ErrOccured ? RETURN_ERROR : RETURN_OK);

	unless(Options[OPT_QUIET])
		VPrintf("System state:\n"
						"\tDrive click is %s\n"
						"\tStar is %s\n"
						"\tPipe char is %s\n"
						"\tMulti command char is %s\n"
						"\tAlert lasts %ld frames\n",(LONG *)States);

	FreeArgs(Args);
NoArgs:
	CloseLibrary((struct Library *)DOSBase);
InvalidDOS:
	return(RC);
}
