/* PowerWindows PIO for PrefsAttack */

#include <OSIncludes.h>
#pragma header

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

#include "/PWPrefs/PrefsAttackIO.h"

#define Pos(c,s) (strchr((s),(c)) ? (UWORD) ((ULONG)strchr((s),(c)) - (ULONG)(s)) : -1 )

struct IntuitionBase *IntuitionBase;
extern struct Library *DOSBase;

struct pioScan *ScanMessage;

static char *InfoText=
	"\33c\33bPowerWindows PIO V 0.7 ("__DATE2__")\n"
	"\n"
	"\33n(C) Copyright 1997 by Georg Steger.\n"
	"All rights reserved!";

char DefaultName[257] = "S:PowerWindows.config";

#define NUM_Bools (sizeof(BoolKeyWords)/sizeof(STRPTR)-1)
#define NUM_Longs (sizeof(LongKeyWords)/sizeof(STRPTR)-1)
#define NUM_Strings (sizeof(StringKeyWords)/sizeof(STRPTR)-1)

static STRPTR BoolKeyWords[] =
{
	"ALLPLANES",
	"SCANSCREENS",
	"CASESENSITIVE",
	"ICONIFYCASESENSITIVE",
	"ICONIFYGADGET",
	"NOMOUSEFREEZE",
	"SAFEMOVEWINDOW",
	"SAFELOCKLAYER",
	"NOICONS",
	"DONTICONIFYWB",
	"NOREQPATCH",
	"AVOIDDOUBLECLICKS",
	"WBICONPOPUP",
	"ICONACTIVATE",
	"NO_OUTOFSCREEN",
	"POPTOFRONT",
	"NOREFRESHKILL",
	"SMARTWIN",
	"ICONCLOSEGAD",
	"OPAQUEMOVE",
	"MAGICMENU_SH",
	"OPAQUE_NOSMART",
	"OPAQUE_NOSIMPLE",
	"OPAQUE_NOSUPER",
	"MULTICX_SM",

	"TASKSONLY",
	"ICONIFYTASKSONLY",
	"SAFEOPAQUE",
	"REFRESHIT",
	"NOICONDRAG",
	"NODGPATCH",
	"FORCEAUTOADJUST",
	0
};

static STRPTR LongKeyWords[]=
{
	"MAXSPPERIOD",
	"ICONIFYOFFSET",
	"DEADLOCK_SEC",
	"DEADLOCK_MIC",
	"DEADLOCK_PRI",
	"MOUSEFACTOR",
	"MINICONWIDTH",
	"ICONPOS_OFFX",
	"ICONPOS_OFFY",
	"ICONPOS_SPACEX",
	"ICONPOS_SPACEY",
	"MINWINWIDTH",
	"SDEPTH_OFFSET",
	"OPAQUE_SPEED",
	"OPAQUE_MAXDEPTH",
	"OPAQUE_MAXPIXELS",
	"OPAQUE_MAXBYTES",
	
	"INPUTPRI",
	0
};

static STRPTR StringKeyWords[]=
{
	"TASK",
	"ICONIFYTASK",
	"MARKER",
	"NORMALQUALIFIER",
	"FORCEQUALIFIER",
	"MULTIQUALIFIER",
	"NORMALBUTTON",
	"FORCEBUTTON",
	"MULTIBUTTON",
	"ICONPOS",
	"ICONWIDTH",
	"IGLOOK",
	"ICONFONT",

	"EXT_WINDOWCHECKER",
	"EXT_SCREENCHECKER",
	"EXT_ICONRENDERER",
	
	"ICONDEPTH",
	"HOT_ICONSTOFRONT",
	"HOT_ICONSTOBACK",
	"HOT_DEICONIFYALL",
	"HOT_WINDOWIN",
	"HOT_ALLWINDOWSIN",
	"HOT_ICONIFY",
	"HOT_PATCHSCREEN",
	"HOT_UNPATCHSCREEN",
	0
};

char UsedFileName[257];
char ErrorTxt[257];
char ErrorHeader[257];
char TextLine[257];
char CommandLine[257];

STRPTR UsedFilename;
STRPTR ConfigMemory;
STRPTR ConfigPos;

LONG ErrorID;

BPTR MyHandle;
BYTE ScanMode;

BOOL BoolOption,KeyWordFound,IsFirstGroup,IsFirstPage;

enum {SCAN_DUMMY,SCAN_LOAD,SCAN_SAVE};
		
/*====================================================================*/

static void ShowMessage(STRPTR msg)
{
	struct EasyStruct es={sizeof(struct EasyStruct),
								 0,
								 "PowerWindows PIO",
								 NULL,
								 "OK"};
	
	es.es_TextFormat=msg;
	EasyRequestArgs(NULL,&es,NULL,NULL);
}

static void DOSError(STRPTR filename,LONG err)
{
	sprintf(ErrorHeader,"Error while accessing \"%s\":",filename);

	Fault(err,ErrorHeader,ErrorTxt,256);
	ShowMessage(ErrorTxt);
}

static void InitLine(void)
{
	WORD i,i2;
	BOOL DoUpper,IsFound,KillSP;

	i2=strlen(TextLine);
	i=0;CommandLine[0]=0;

	DoUpper=TRUE;
	IsFound=FALSE;
	KillSP=TRUE;

	while (i<i2)
	{
		if ((TextLine[i]=='=') && (!IsFound))
		{
			IsFound=TRUE;
			strcpy(CommandLine,TextLine);CommandLine[i]=0;
			if ((strcmp(CommandLine,"TASK")==0) ||
				 (strcmp(CommandLine,"ICONIFYTASK")==0) ||
				 (strstr(CommandLine,"HOT_")) ||
				 (strstr(CommandLine,"EXT_")) ||
				 (strstr(CommandLine,"FONT"))) DoUpper=FALSE;

		} else {						
			if (TextLine[i]>='a' && TextLine[i]<='z' && DoUpper) TextLine[i]=toupper(TextLine[i]);
			if (TextLine[i]==9 || TextLine[i]==' ' || TextLine[i]=='"')
			{
				if (TextLine[i]=='"') KillSP= !KillSP;
				if (KillSP || (TextLine[i]=='"'))
				{
					memmove(&TextLine[i],&TextLine[i+1],strlen(TextLine)-i);
					--i2;
					--i;
				}
			}
		}
		i++;
	}

	i=Pos('=',TextLine);
	if (i>0)
	{
		BoolOption=FALSE;
		if (i<strlen(TextLine)-1)
		{
			memmove(TextLine,&TextLine[i+1],strlen(TextLine)-i);
		} else TextLine[0]=0;
	} else BoolOption=TRUE;

/* Kill End-Of-Line Rems */

	i=strlen(TextLine)-1;
	while (i>=0)
	{
		if (TextLine[i]==';')
		{
			TextLine[i]=0;
			break;
		}
		i--;
	}
	
	
}

static void FindBool(char *KeyWord)
{
	if (!KeyWordFound)
	{
		if (strcmp(KeyWord,TextLine)==0)
		{
			KeyWordFound=TRUE;
			ScanMessage->KeyWord=KeyWord;
			ScanMessage->Long_Value=TRUE;
			ScanMessage->ScanType=SCANTYP_LONG;
		}
	}
}

static void FindString(char *KeyWord)
{
	if (!KeyWordFound)
	{
		if (strcmp(KeyWord,CommandLine)==0)
		{
			KeyWordFound=TRUE;
			ScanMessage->KeyWord=KeyWord;
			ScanMessage->String_Value=TextLine;
			ScanMessage->ScanType=SCANTYP_STRING;
		}
	}
}

static void FindLong(char *KeyWord)
{
	if (!KeyWordFound)
	{
		if (strcmp(KeyWord,CommandLine)==0)
		{
			KeyWordFound=TRUE;
			ScanMessage->KeyWord=KeyWord;
			ScanMessage->Long_Value=strtol(TextLine,NULL,0);
			ScanMessage->ScanType=SCANTYP_LONG;
		}
	}
}

static void MyWrite(APTR mem,LONG size)
{
	LONG l;

	if (!(MyHandle)) return;
	
	l=Write(MyHandle,mem,size);
	if (l!=size)
	{
		ErrorID=IoErr();
		Close(MyHandle);
		MyHandle=0;
	}
}

static void WriteString(STRPTR s)
{
	MyWrite(s,strlen(s));
}

	
/*====================================================================*/

static LONG PIO_Init(struct pioInit *msg)
{
	LONG rc=PIOR_FAIL;
	
	if ((IntuitionBase=(struct IntuitionBase *)OpenLibrary("intuition.library",39)))
	{
		if ((DOSBase=OpenLibrary("dos.library",39)))
		{
			if (msg->Parameters) strcpy(DefaultName,msg->Parameters);
			rc=PIOR_OK;
		} else {
			CloseLibrary((struct Library *)IntuitionBase);
		}
	}
	return rc;
}

/*====================================================================*/

static void PIO_Exit(struct pioExit *msg)
{
	if (IntuitionBase) CloseLibrary((struct Library *)IntuitionBase);
	if (DOSBase) CloseLibrary(DOSBase);
	if (MyHandle) Close(MyHandle);
	if (ConfigMemory) FreeVec(ConfigMemory);
}

/*====================================================================*/

static void PIO_Info(struct pioInfo *msg)
{
	msg->Information=InfoText;
}

/*====================================================================*/

static LONG PIO_Load(struct pioLoad *msg)
{
	LONG rc=PIOR_FAIL;
	ULONG len;
	
	if (msg->Filename)
	{
		strcpy(UsedFileName,msg->Filename);
	} else {
		strcpy(UsedFileName,DefaultName);
	}
	
	if (!(MyHandle=Open(UsedFileName,MODE_OLDFILE)))
	{
		DOSError(UsedFileName,IoErr());
	} else {
		len=Seek(MyHandle,0,OFFSET_END);
		if (len == ~0)
		{
			DOSError(UsedFileName,IoErr());
			Close(MyHandle);MyHandle=0;
		} else {
			len=Seek(MyHandle,0,OFFSET_BEGINNING);
			if (len == ~0)
			{
				DOSError(UsedFileName,IoErr());
				Close(MyHandle);MyHandle=0;
			} else {
				if (!(ConfigMemory=AllocVec(len+1,MEMF_ANY|MEMF_CLEAR)))
				{
					ShowMessage("Out of memory!");
					Close(MyHandle);MyHandle=0;
				} else {
					if (Read(MyHandle,ConfigMemory,len) != len)
					{
						DOSError(UsedFileName,IoErr());
						Close(MyHandle);MyHandle=0;
						FreeVec(ConfigMemory);ConfigMemory=NULL;
					} else {
						Close(MyHandle);MyHandle=0;
						ConfigPos=ConfigMemory;
						ScanMode=SCAN_LOAD;
						rc=PIOR_OK;
					}
				}
			}
		}
	}
	return rc;	
}

/*====================================================================*/

static LONG PIO_Save(struct pioSave *msg)
{
	LONG rc=PIOR_FAIL;
	
	if (msg->Filename)
	{
		strcpy(UsedFileName,msg->Filename);
	} else {
		strcpy(UsedFileName,DefaultName);
	}
	
	if (!(MyHandle=Open(UsedFileName,MODE_NEWFILE)))
	{
		DOSError(UsedFileName,IoErr());
	} else {
		ScanMode=SCAN_SAVE;
		IsFirstGroup=TRUE;
		rc=PIOR_OK;
	}
	return rc;	
}
	
/*====================================================================*/
			
static LONG PIO_ScanLoad(struct pioScan *msg)
{
	LONG rc=PIOR_OK;
	WORD i=0;
	BOOL LastScan=FALSE,OK=FALSE;
	char c;

	ScanMessage=msg;

	while ((!OK) && (!LastScan))
	{
		c= *ConfigPos++;
		switch (c)
		{
			case 0:
				LastScan=TRUE;
				rc=PIOR_ENDSCAN;

			case 10:
				OK=TRUE;
				break;
				
			default:
				TextLine[i++]=c;
		}
		if (OK)
		{
			if ((TextLine[0]==' ') || (TextLine[0]==';') ||
			    (TextLine[0]==0) || (TextLine[0]==10) ||
			    (TextLine[0]=='\t') || (TextLine[0]=='*'))
			{
				OK=FALSE;i=0;
			}
		}
	}
	TextLine[i]=0;

	InitLine();

	msg->ScanType=SCANTYP_NOTHING;

	if (OK)
	{

		KeyWordFound=FALSE;
		if (BoolOption)
		{
	
			for (i=0;i<NUM_Bools;i++)
			{
				FindBool(BoolKeyWords[i]);
			}
			if (!KeyWordFound) msg->ScanType=SCANTYP_UNKNOWN;
	
		} else {
	
			for (i=0;i<NUM_Longs;i++)
			{
				FindLong(LongKeyWords[i]);
				if (KeyWordFound) break;
			}
	
			if (!KeyWordFound)
			{
				for (i=0;i<NUM_Strings;i++)
				{
					FindString(StringKeyWords[i]);
				}
			}
			
			if (!KeyWordFound) msg->ScanType=SCANTYP_UNKNOWN;
	
		}
		
	} /* if (OK) */
	
	if (rc==PIOR_ENDSCAN)
	{
		FreeVec(ConfigMemory);
		ConfigMemory=NULL;
	}

	return rc;
}

/*====================================================================*/

static LONG PIO_ScanSave(struct pioScan *msg)
{
	LONG rc=PIOR_OK;
	WORD i,i2;
	BOOL b;
	
	switch (msg->ScanType)
	{
		case SCANTYP_GROUP:
			if (!IsFirstGroup) WriteString("\n\n\n\n");
			IsFirstGroup=FALSE;

			for (i=0;i<76;i++)
			{
				TextLine[i]='*';
			}
			TextLine[i]=0;
			strcat(TextLine,"\n");
			WriteString(TextLine);

			ErrorTxt[0]='*';
			for (i=1;i<=74;i++)
			{
				ErrorTxt[i]=' ';
			}
			ErrorTxt[75]='*';
			ErrorTxt[76]='\n';
			ErrorTxt[77]=0;
			
			WriteString(ErrorTxt);
			
			strcpy(CommandLine,"* ");
			strcat(CommandLine,msg->String_Value);

			i2=75-strlen(CommandLine);			
			for (i=0;i<i2;i++)
			{
				strcat(CommandLine," ");
			}
			strcat(CommandLine,"*\n");
			WriteString(CommandLine);
			WriteString(ErrorTxt);
			WriteString(TextLine);
			WriteString("\n");
			break;
			
		case SCANTYP_PAGE:
			strcpy(TextLine," \n\n ====/ ");
			strcat(TextLine,msg->String_Value);
			strcat(TextLine," /");
			
			i2=77-strlen(TextLine);
			for (i=0;i<=i2;i++)
			{
				strcat(TextLine,"=");
			}
			strcat(TextLine,"\n\n\n");
			WriteString(TextLine);
			break;
			
		case SCANTYP_LONG:
			b=FALSE;
			for (i=0;i<NUM_Bools;i++)
			{
				if (stricmp(msg->KeyWord,BoolKeyWords[i])==0)
				{
					if (msg->Long_Value!=0)
					{
						sprintf(TextLine,"%s\n\n",msg->KeyWord);
					} else {
						sprintf(TextLine," ;%s\n\n",msg->KeyWord);
					}
					WriteString(TextLine);
					b=TRUE;
					break;
				}
			}
			if (!b)
			{
				sprintf(TextLine,"%s = %ld\n\n",msg->KeyWord,msg->Long_Value);
				WriteString(TextLine);
			}
			break;

		case SCANTYP_STRING:
			if ((strchr(msg->String_Value,' ')) ||
			    (strchr(msg->String_Value,'\t')))
			{
				sprintf(TextLine,"%s = \"%s\"\n\n",msg->KeyWord,msg->String_Value);
			} else {
				if (msg->String_Value[0])
				{
					sprintf(TextLine,"%s = %s\n\n",msg->KeyWord,msg->String_Value);
				} else {
					sprintf(TextLine," ;%s =\n\n",msg->KeyWord);
				}
			}
			WriteString(TextLine);
			break;
			
		case SCANTYP_ENDSCAN:
			if (MyHandle)
			{
				Close(MyHandle);
				MyHandle=0;
			} else {
				DOSError(UsedFileName,ErrorID);
				rc=PIOR_FAIL;
			}
			break;
	}	/* switch (msg->ScanType) */
	
	return rc;
}

/*====================================================================*/

/*====================================================================*/

LONG main(Msg msg)
{
	LONG rc;

	switch (msg->MethodID)
	{
		case PIOM_INIT:
			rc=PIO_Init((struct pioInit *)msg);
			break;

		case PIOM_EXIT:
			PIO_Exit((struct pioExit *)msg);
			break;
			
		case PIOM_INFO:
			PIO_Info((struct pioInfo *)msg);
			break;
			
		case PIOM_LOAD:
			rc=PIO_Load((struct pioLoad *)msg);
			break;
			
		case PIOM_SAVE:
			rc=PIO_Save((struct pioSave *)msg);
			break;

		case PIOM_SCAN:
			switch (ScanMode)
			{
				case SCAN_LOAD:
					rc=PIO_ScanLoad((struct pioScan *)msg);
					break;

				case SCAN_SAVE:
					rc=PIO_ScanSave((struct pioScan *)msg);
					break;
			}
			break;
	}
	
	return rc;
}


