#define NAME     "ProcessIcon"
#define REVISION "10"
#define SDI_ENDCODE

/* Programmheader

	Name:		ProcessIcon
	Author:		SDI
	Distribution:	PD
	Description:	processes .info files
	Compileropts:	-
	Linkeropts:	-l amiga

 1.0   01.93.97 : first version
 1.1   03.03.97 : options KILLSTACKSIZE, KILLDEFTOOL, VIEW
 1.2   05.03.97 : added SIT and CIT options
 1.3   29.03.97 : not existing TO produces icon
 1.4   13.06.97 : lots of changes, renamed from CopyIconImage
 1.5   14.06.97 : added more data to VIEW option
 1.6   01.07.97 : fixed problem with DrawerData
 1.7   09.11.97 : added UNSNAP function
 1.8   05.02.98 : IMGSRC became REFICON, added COPYIMAGE instead of autocopy
 1.9   01.09.98 : better VIEW output
 1.10  08.05.99 : added REMAP option
*/

#include <proto/dos.h>
#include <proto/icon.h>
#include <proto/exec.h>
#define SDI_TO_ANSI
#include "SDI_ASM_STD_protos.h"
#include "SDI_defines.h"

#define PARAM (STRPTR)  "ICON/A,REFICON,VIEW/S,OPT=OPTIMIZE/S,"		\
			"US=UNSNAP/S,REMAP/S,"				\
			"SDT=SETDEFTOOL,SIT=SETICONTYPE,"		\
			"SBP=SETBITPLANES/N,SXP=SETXPOS/N,"		\
			"SYP=SETYPOS/N,"				\
			"KDT=KILLDEFTOOL/S,KTT=KILLTOOLTYPES/S,"	\
			"KSS=KILLSTACKSIZE/S,KDD=KILLDRAWERDATA/S,"	\
			"CDT=COPYDEFTOOL/S,CIT=COPYICONTYPE/S,"		\
			"CTT=COPYTOOLTYPES/S,CDD=COPYDRAWERDATA/S,"	\
			"CII=COPYICONIMAGE/S"
struct Args {
    STRPTR	icon;
    STRPTR	reficon;
    ULONG	view;
    ULONG	optimize;
    ULONG 	unsnap;
    ULONG	remap;
    STRPTR	setdeftool;
    STRPTR	seticontype;
    ULONG *	setbitplanes;
    ULONG *	setxpos;
    ULONG *	setypos;
    ULONG	killdeftool;
    ULONG	killtooltypes;
    ULONG	killstacksize;
    ULONG	killdrawerdata;
    ULONG	copydeftool;
    ULONG	copyicontype;
    ULONG	copytooltypes;
    ULONG	copydrawerdata;
    ULONG	copyiconimage;
};

struct RDArgs*		rda		= 0;
struct Library *	IconBase	= 0;
ULONG			DosVersion	= 37;
struct DiskObject *	dobj		= 0;
struct DiskObject *	dobjsrc		= 0;
struct DiskObject *	dobjdrw		= 0;

STRPTR IconTypeRecog[] = 
{0, "Disk", "Drawer", "Tool", "Project", "Garbage", "Device", "Kick", "AppIcon"};

static void testgroup(STRPTR a, ULONG b, ULONG c)
{
  if((a && (b || c)) || (b && c))
  {
    SetIoErr(ERROR_TOO_MANY_ARGS);
    End(RETURN_FAIL);
  }
}

static void kill(ULONG a, APTR b)
{
  if(a && *((ULONG *)b))
    *((ULONG *)b) = 0;
}

static void set(STRPTR a, APTR b)
{
  if(a)
    *((STRPTR *)b) = a;
}

static void RemapImage(struct Image *im)
{
  ULONG w, i, j, k, d;
  UWORD *ptr;

  w = (im->Width+15)>>4; /* dive by 16 */
  ptr = im->ImageData;

  if(im->Depth == 1)
  {
    for(i = 0; i < im->Height; ++i)
    {
      for(j = 0; j < w; ++j)
        ptr[i*w + j] ^= 0xFFFF;
      if((k = (w<<4) - im->Width))
      {
        /* clear last unused bits */
        ptr[i*w + j - 1] &= (0xFFFF >> k) << k;
      }
    }
  }
  else
  {
    for(i = 0; i < im->Height; ++i)
    {
      for(j = 0; j < w; ++j)
      {
        k = ptr[i*w + j] ^ ptr[(im->Height + i)*w + j];
        for(d = 2; d < im->Depth; ++d)
          k &= (~ptr[(im->Height*d +i)*w + j]);
        ptr[i*w + j] ^= k;
        ptr[(im->Height + i)*w + j] ^= k;
      }
      if((k = (w<<4) - im->Width))
      {
        /* clear last unused bits */
        ptr[i*w + j - 1] &= (0xFFFF >> k) << k;
        ptr[(im->Height + i)*w + j - 1] &= (0xFFFF >> k) << k;
      }
    }
  }
}

void main(void)
{
  STRPTR empty = 0;
  struct Args args;
  ULONG s;

  memset(&args, 0, sizeof(struct Args));

  if(!(rda = ReadArgs(PARAM, (LONG *) &args, 0)))
    End(RETURN_FAIL);

  testgroup(args.setdeftool,	args.killdeftool,	args.copydeftool);
  testgroup(0,			args.killtooltypes,	args.copytooltypes);
  testgroup(args.seticontype,	0,			args.copyicontype);
  testgroup(0,			args.killdrawerdata,	args.copydrawerdata);

  if((args.unsnap && (args.setxpos || args.setypos)) || (!args.reficon &&
  (args.copydeftool || args.copytooltypes || args.copyicontype ||
  args.copydrawerdata || args.copyiconimage)))
  {
    SetIoErr(ERROR_TOO_MANY_ARGS);
    End(RETURN_FAIL);
  }

  s = strlen(args.icon);
  if(!strncmp(args.icon+s-5, ".info",5))
    args.icon[s-5] = 0;

  if(
  !(IconBase = OpenLibrary("icon.library", 37)) ||
  !(dobj = GetDiskObjectNew(args.icon)) ||
  !(dobjdrw = GetDefDiskObject(WBDRAWER)))
    End(RETURN_FAIL);

  if(args.view)
  {
    STRPTR *a;

    Printf("Name: %s\n SS: %ld\n IT: %s\n BP: %ld,%ld\n SZ: ",
      args.icon, dobj->do_StackSize, IconTypeRecog[dobj->do_Type],
      ((struct Image *)dobj->do_Gadget.GadgetRender)->Depth,
      (dobj->do_Gadget.SelectRender ?
      ((struct Image *)dobj->do_Gadget.SelectRender)->Depth : 0));
    Printf(dobj->do_CurrentX == NO_ICON_POSITION ? "NOPOS" : "x=%3ld",
      dobj->do_CurrentX);
    Printf(dobj->do_CurrentY == NO_ICON_POSITION ? ", NOPOS" : ", y=%3ld",
      dobj->do_CurrentY);
    Printf(", w=%3ld, h=%3ld\n DT: (%s) %s\n TT: (%s)\n",
      dobj->do_Gadget.Width, dobj->do_Gadget.Height,
      (dobj->do_DefaultTool ? "YES" : "NO"), dobj->do_DefaultTool, 
      (dobj->do_ToolTypes ? (*(dobj->do_ToolTypes) ? "YES" :
      "YES - EMPTY") : "NO"));
    if((a = (STRPTR *) dobj->do_ToolTypes))
      while(*a)
        Printf("  %s\n", *(a++));
    End(RETURN_OK);
  }

  if(args.reficon)
  {
    s = strlen(args.reficon);
    if(!strncmp(args.reficon+s-5, ".info",5))
      args.reficon[s-5] = 0;
    if((dobjsrc = GetDiskObjectNew(args.reficon)))
    {
      if(args.copyiconimage)
      {
        if(dobj->do_CurrentX != NO_ICON_POSITION && dobj->do_CurrentY !=
        NO_ICON_POSITION)
        {
          dobj->do_CurrentX +=
            (dobj->do_Gadget.Width>>1) - (dobjsrc->do_Gadget.Width>>1);
          dobj->do_CurrentY +=
            dobj->do_Gadget.Height - dobjsrc->do_Gadget.Height;
          /* 'down middle position' of gadget should be same after image copy */
        }
        dobj->do_Gadget = dobjsrc->do_Gadget;	/* copy gadget structures */
      }
      if(args.copydeftool)	dobj->do_DefaultTool = dobjsrc->do_DefaultTool;
      if(args.copytooltypes)	dobj->do_ToolTypes = dobjsrc->do_ToolTypes;
      if(args.copyicontype)	dobj->do_Type = dobjsrc->do_Type;
      if(args.copydrawerdata)	dobj->do_DrawerData = dobjsrc->do_DrawerData;
    }
    else
      End(RETURN_FAIL);
  }

  if(args.seticontype)
  {
    UBYTE i = 0;

    while(++i <= WBAPPICON && stricmp(IconTypeRecog[i], args.seticontype))
      ;
    if(i <= WBAPPICON)
      dobj->do_Type = i;

    if(dobj->do_Type == WBDISK || dobj->do_Type == WBGARBAGE ||
       dobj->do_Type == WBDRAWER)
      dobj->do_DrawerData = dobjdrw->do_DrawerData;
  }

  if(args.remap)
  {
    RemapImage((struct Image *) dobj->do_Gadget.GadgetRender);
    if(dobj->do_Gadget.SelectRender)
      RemapImage((struct Image *) dobj->do_Gadget.SelectRender);
  }

  if(args.setbitplanes)
  {
    ((struct Image *) dobj->do_Gadget.GadgetRender)->Depth =
    *args.setbitplanes;
    if(dobj->do_Gadget.SelectRender)
      ((struct Image *) dobj->do_Gadget.SelectRender)->Depth =
      *args.setbitplanes;
  }

  if(args.setxpos)		dobj->do_CurrentX = *args.setxpos;
  if(args.setypos)		dobj->do_CurrentY = *args.setypos;
  set(args.setdeftool, &dobj->do_DefaultTool);

  if(args.killdrawerdata)
  {
    dobj->do_DrawerData = dobjdrw->do_DrawerData;
    if(dobj->do_Type != WBDISK && dobj->do_Type != WBGARBAGE &&
    dobj->do_Type != WBDRAWER)
      dobj->do_DrawerData = 0;
  }
    
  if(args.unsnap)		dobj->do_CurrentX = dobj->do_CurrentY = NO_ICON_POSITION;

  if(dobj->do_Type == WBPROJECT || dobj->do_Type == WBTOOL)
  {
    if(!dobj->do_ToolTypes)
      dobj->do_ToolTypes = (char **) &empty;
    kill(args.killtooltypes, dobj->do_ToolTypes);
  }
  else
    kill(args.killtooltypes, &dobj->do_ToolTypes);

  kill(args.killstacksize, &dobj->do_StackSize);
  kill(args.killdeftool, &dobj->do_DefaultTool);

  if(args.optimize)
  {
    if(dobj->do_Type != WBDISK && dobj->do_Type != WBPROJECT)
      dobj->do_DefaultTool = 0;
    if(dobj->do_Type != WBPROJECT && dobj->do_Type != WBTOOL)
      dobj->do_ToolTypes = 0;
    if(dobj->do_Type != WBDISK && dobj->do_Type != WBGARBAGE &&
    dobj->do_Type != WBDRAWER)
      dobj->do_DrawerData = 0;
  }

  End(PutDiskObject(args.icon, dobj) ? RETURN_OK : RETURN_FAIL);
}

void end(void)
{
  if(dobj)		FreeDiskObject(dobj);
  if(dobjdrw)		FreeDiskObject(dobjdrw);
  if(dobjsrc)		FreeDiskObject(dobjsrc);
  if(IconBase)		CloseLibrary(IconBase);
  if(rda)		FreeArgs(rda);
}

