/*
 *	AddIcon.c - Copyright © 1991 by S.R. & P.C.
 *
 *	Created:	23 May 1992  12:00:40
 *	Modified:	28 Jul 1992  08:56:19
 *
 *	Make>> cc -qv -qf -pl -sb -wu -wd -wp -wr -wc -hi aztec:include/x.dmp -so <file>.c
 *	Make>> ln -g <file>.o -lstartup -lstring
 */

#include "WhatIsBase.h"
#include "string_lib.h"

extern struct ExecBase *SysBase;
extern struct DOSLibrary *DOSBase;

struct WhatIsBase *WhatIsBase;
struct Library *IconBase;

#define MAXFULLNAMELEN 255

char *Template = "FileName,ONLY/K,FILES/S,DIRS/S,QUIET/S,FLOAT/S,OVERRIDE/S,ALL/S";

#define ARG_FileName 0
#define ARG_ONLY		1
#define ARG_FILES		2
#define ARG_DIRS		3
#define ARG_QUIET		4
#define ARG_FLOAT		5
#define ARG_OVERRIDE	6
#define ARG_ALL		7
#define ARG_ENDARG	8
char *CliHelp = "AddIcon V1.1 [32m© 1992 S.R. & P.C.[31m\n\
Usage: AddIcon <FileName> [ONLY <FileType>] [FILES] [DIRS] [QUIET] [FLOAT] [OVERRIDE] [ALL]\n\
FileName: the object name you want to add icon to.\n\
ONLY FileType: Add icon only to that type\n\
FILES: add icon to files only.\n\
DIRS: add icon to dirs only.\n\
QUIET: if set, no info printed.\n\
FLOAT: UnSnapshot icon\n\
OVERRIDE: Override existing icon if present\n\
ALL: enter subdir.\n";

LONG SPrintf(UBYTE * buf, UBYTE * fmt,...);

FileType WhatIsTags(char *Name, Tag FirstTag,...)
{
	return (WhatIsBase) ? WhatIs(Name, (struct TagItem *) & FirstTag) : TYPE_UNSCANNED;
}

/* FIB can be null but give it if you alredy have it. */
BOOL AddIcon(char *FileName, FileType OnlyType, BOOL Quiet, BOOL Float, BOOL Override, struct DiskObject ** LastDOb, FileType * LastType, struct FileInfoBlock * FIB)
{
	char *IconName = NULL;
	char Buf[255];
	FileType Type;
	LONG WBType = 0;
	BOOL Idem;
	BOOL Ok = FALSE;	/* assume the worst */
	struct DiskObject *dob = NULL;
	BPTR L;

	if (!Quiet) {
		SPrintf(Buf, "\"%s\"", FileName);
		Printf("%-32s\t", Buf);
		Flush(Output());
	}
	SPrintf(Buf, "%s.info", FileName);
	if (!Override && (L = Lock(Buf, ACCESS_READ))) {
		UnLock(L);
		if (!Quiet)
			PutStr("Icon already exist.\n");
		return TRUE;
	}
	Type = WhatIsTags(FileName, WI_Deep, DEEPTYPE, (FIB) ? WI_FIB : TAG_IGNORE, FIB, TAG_DONE);
	if (!Quiet) {
		Printf("%-9s ", GetIDString(Type));
		Flush(Output());
	}
	if ((OnlyType != TYPE_UNSCANNED) && CmpFileType(Type, OnlyType)) {
		if (!Quiet)
			PutStr("Type not desired\n");
		return TRUE;
	}
	Idem = !CmpFileType(Type, *LastType);

	if (CmpFileType(Type, TYPE_UNKNOWNFILETYPE)) {
		if (!CmpFileType(Type, GetIDType("Volume"))) {
			IconName = "def_Disk";
			FileName = "Disk";
			WBType = WBDISK;	/* To use ROM resident icon if no def_Tool defined in ENV:Sys */
		}
		else if (!CmpFileType(Type, GetIDType("Dir"))) {
			IconName = "def_Drawer";
			WBType = WBDRAWER;	/* To use ROM resident icon if no def_Tool defined in ENV:Sys */
		}
		else {
			IconName = GetIconName(Type);
			if (!StriCmp(IconName, "def_Tool"))
				WBType = WBTOOL;	/* To use ROM resident icon if no def_Tool defined in ENV:Sys */
			else if (!StriCmp(IconName, "def_Project"))
				WBType = WBPROJECT;	/* To use ROM resident icon if no def_Project defined in ENV:Sys */
		}
		if (!Quiet) {
			Printf("\"%s\"..", IconName);
			Flush(Output());
		}
		SPrintf(Buf, "Env:Sys/%s", IconName);
		if ((dob = (Idem) ? *LastDOb : ((WBType) ? GetDefDiskObject(WBType) : GetDiskObject(Buf)))) {
			if (Float) {
				dob->do_CurrentX = NO_ICON_POSITION;
				dob->do_CurrentY = NO_ICON_POSITION;
			}
			if (PutDiskObject(FileName, dob)) {
				PutStr(".Ok\n");
				if (!Idem) {
					if (*LastDOb)
						FreeDiskObject(*LastDOb);
					*LastDOb = dob;	/* memorise the current icon */
					*LastType = Type;	/* memorise the current type */
				}
				Ok = TRUE;
			}
			else
				PutStr("Can't write icon !\n");
		}
		else
			PutStr("Can't read icon.\n");
	}
	else
		PutStr("Unknown file.\n");

	return Ok;
}

long main(int argc, char *argv[])
{
	long rc = 0;
	char *FileName;
	BOOL Files, Dirs, Quiet, Float, Override, All;
	char SubDirs[255];
	UBYTE NumSubDir = 0;

	FileName = argv[ARG_FileName];
	//StrCat("#?[~(#?.info)]",);
	Files = (BOOL) argv[ARG_FILES];
	Dirs = (BOOL) argv[ARG_DIRS];
	Quiet = (BOOL) argv[ARG_QUIET];
	Float = (BOOL) argv[ARG_FLOAT];
	Override = (BOOL) argv[ARG_OVERRIDE];
	All = (BOOL) argv[ARG_ALL];
	SubDirs[0] = '\0';
	if (!FileName) {
		Printf("%s", CliHelp);
		return 5;
	}

	if (WhatIsBase = (struct WhatIsBase *) OpenLibrary("whatis.library", 0l)) {
		if (IconBase = OpenLibrary("icon.library", 37L)) {
			struct DiskObject *LastDOb = NULL;
			FileType LastType = TYPE_UNKNOWNFILETYPE, OnlyType = TYPE_UNSCANNED;
			struct AnchorPath AP;
			LONG ReturnCode = RETURN_ERROR;
			BPTR StartDir;

			if (argv[ARG_ONLY])
				OnlyType = GetIDType(argv[ARG_ONLY]);
			StartDir = CurrentDir(((struct Process *) SysBase->ThisTask)->pr_CurrentDir);
			AP.ap_BreakBits = SIGBREAKF_CTRL_C;	/* Break on these bits	*/
			AP.ap_Strlen = 0;
			//MAXFULLNAMELEN;
			AP.ap_Flags = (All) ? APF_DODOT : APF_DODOT | APF_DOWILD;	/* allow convertion of '.' to CurrentDir */
			/*  Well  I have one probleme here:  how corectly handle the
				ALL  flags:  if the user specify a pattern the MatchNext(
				hidden)  all  file  and  DIRS  which  don't  match to the
				pattern,  so  I  don't  see  dir  and  in  fact can't ask
				MatchNext()  to  enter it.  This limitation is STUPID and
				important  liumitation.   I  hope is only because I don't
				know how to do it.  I hope...
			*/
			for (ReturnCode = MatchFirst(FileName, &AP);
			     ReturnCode == 0;
			     ReturnCode = MatchNext(&AP)
				) {
				if (AP.ap_Flags & APF_DirChanged) {
					CurrentDir(AP.ap_Current->an_Lock);
				}
				if (AP.ap_Info.fib_DirEntryType > 0) {
					if (AP.ap_Flags & APF_DIDDIR) {
						SubDirs[--NumSubDir] = '\0';
					}
					else if (All) {
						if (!Quiet)
							Printf("[33m\"%s\"[31m\n", AP.ap_Info.fib_FileName);
						if (!Files) {
							Printf("%s", SubDirs);
							AddIcon(AP.ap_Info.fib_FileName, OnlyType, Quiet, Float, Override, &LastDOb, &LastType, &AP.ap_Info);
						}
						SubDirs[NumSubDir++] = '/';
						SubDirs[NumSubDir] = '\0';

						/* make it enter the directory */
						AP.ap_Flags |= APF_DODIR;
					}
					/* clear the completed directory flag */
					AP.ap_Flags &= ~APF_DIDDIR;
				}
				else {
					/* Here is code for handling each particular file */
					if (!Dirs && !MatchPatternNoCase("\X80.INFO", AP.ap_Info.fib_FileName)) {
						Printf("%s", SubDirs);
						AddIcon(AP.ap_Info.fib_FileName, OnlyType, Quiet, Float, Override, &LastDOb, &LastType, &AP.ap_Info);
					}
				}
			}
			MatchEnd(&AP);	/* This absolutely, positively must be called, all of the time. */
			CurrentDir(StartDir);
			if (ReturnCode != ERROR_NO_MORE_ENTRIES) {
				PrintFault(ReturnCode, NULL);
			}
			if (LastDOb)
				FreeDiskObject(LastDOb);

			CloseLibrary(IconBase);
		}
		else
			Printf("Can't open icon.library !\n");

		CloseLibrary((struct Library *) WhatIsBase);
	}
	else
		Printf("Can't open whatis.library !\n");

	return rc;
}
