/*                                                               -*- C -*-
 *  IM.C
 *
 *  (c)Copyright 1995 by Tobias Ferber,  ukjg@rz.uni-karlsruhe.de
 *
 *  This file is part of the IconTools distribution
 *
 *  IconMaker is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published
 *  by the Free Software Foundation; either version 1 of the License,
 *  or (at your option) any later version.
 *
 *  IconMaker is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; see the file COPYING.  If not, write to
 *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include "version.h"
static char versiontag[]= "$VER: $Id: im.c,v 1.6 1995/07/22 16:41:12 tf Exp $";

#include <intuition/intuition.h>
#include <intuition/intuitionbase.h>
#include <graphics/gfxbase.h>
#include <workbench/workbench.h>
#include <workbench/icon.h>

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

#include "iffp/ilbm.h"
#include "iffp/ilbmapp.h"

#ifndef IFFPARSENAME
#define IFFPARSENAME "iffparse.library"
#endif

extern BOOL PutDiskObject(char *, struct DiskObject *);

void display_version_information(void)
{
  static char license[]=
    "IconMaker is free software; you can redistribute it and/or modify\n"
    "it under the terms of the GNU General Public License as published\n"
    "by the Free Software Foundation; either version 1 of the License,\n"
    "or (at your option) any later version.\n"
    "\n"
    "IconMaker is distributed in the hope that it will be useful,\n"
    "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
    "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
    "GNU General Public License for more details.\n"
    "\n"
    "You should have received a copy of the GNU General Public License\n"
    "along with this program; see the file COPYING.  If not, write to the\n"
    "Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n"
    ;

  puts("\nIconMaker/IM Version " VERSION " (compiled " __DATE__ ", " __TIME__ ")\n"
       "(c)Copyright 1995 by Tobias Ferber, ukjg@rz.uni-karlsruhe.de\n");

  puts(license);
}

UWORD *ImageDataFromBitMap(struct BitMap *bm, WORD width, WORD height);

/* System */

struct Library *GfxBase      = NULL;
struct Library *IFFParseBase = NULL;
struct Library *IconBase     = NULL;

/*
 *  These are the default values
 */

static struct Image gr = { 0, 0, 0, 0, 0, NULL, 0, 0, NULL };  /* GadgetRender */
static struct Image sr = { 0, 0, 0, 0, 0, NULL, 0, 0, NULL };  /* SelectRender */

static char *tt[] = { "FILETYPE=ILBM", NULL };

static struct DrawerData dd = {
 { 60,                             /* dd_NewWindow.LeftEdge */
   50,                             /* dd_NewWindow.TopEdge */
   330,                            /* dd_NewWindow.Width */
   140,                            /* dd_NewWindow.Height */
   255,                            /* dd_NewWindow.DetailPen */
   255,                            /* dd_NewWindow.BlockPen */
   NULL,                           /* dd_NewWindow.IDCMPFlags */
   WFLG_SIZEGADGET
   | WFLG_DRAGBAR
   | WFLG_DEPTHGADGET
   | WFLG_CLOSEGADGET
   | WFLG_SIZEBRIGHT
   | WFLG_SIZEBBOTTOM
   | WFLG_SIMPLE_REFRESH
   | WFLG_REPORTMOUSE
   | WFLG_ACTIVATE
   | WFLG_NEWLOOKMENUS
   | WFLG_WBENCHWINDOW,            /* dd_NewWindow.Flags */
   NULL,                           /* dd_NewWindow.FirstGadget */
   NULL,                           /* dd_NewWindow.CheckMark */
   NULL,                           /* dd_NewWindow.Title */
   NULL,                           /* dd_NewWindow.Screen */
   NULL,                           /* dd_NewWindow.BitMap */
   0,                              /* dd_NewWindow.MinWidth */
   0,                              /* dd_NewWindow.MinHeight */
   65535,                          /* dd_NewWindow.MaxWidth */
   65535,                          /* dd_NewWindow.MaxHeight */
   WBENCHSCREEN },                 /* dd_NewWindow.Type */
   0,                              /* dd_CurrentX */
   0,                              /* dd_CurrentY */
   3,                              /* dd_Flags */
   0,                              /* dd_ViewModes */
};

static struct DiskObject icon = {
   WB_DISKMAGIC,                   /* do_Magic */
   WB_DISKVERSION,                 /* do_Version */
 { NULL,                           /* do_Gadget.NextGadget */
   0,                              /* do_Gadget.LeftEdge */
   0,                              /* do_Gadget.TopEdge */
   0,                              /* do_Gadget.Width */
   0,                              /* do_Gadget.Height */
   GFLG_GADGHIMAGE|GFLG_GADGIMAGE, /* do_Gadget.Flags */
   GACT_RELVERIFY|GACT_IMMEDIATE,  /* do_Gadget.Activation */
   GTYP_BOOLGADGET,                /* do_Gadget.GadgetType */
   (APTR)&gr,                      /* do_Gadget.GadgetRender */
   (APTR)&sr,                      /* do_Gadget.SelectRender */
   NULL,                           /* do_Gadget.GadgetText */
   0,                              /* do_Gadget.MutualExclude */
   NULL,                           /* do_Gadget.SpecialInfo */
   0,                              /* do_Gadget.GadgetID */
   WB_DISKREVISION },              /* do_Gadget.UserData */
   WBPROJECT,                      /* do_Type */
   "MultiView",                    /* do_DefaultTool */
   &tt[0],                         /* do_ToolTypes */
   NO_ICON_POSITION,               /* do_CurrentX */
   NO_ICON_POSITION,               /* do_CurrentY */
   &dd,                            /* do_DrawerData */
   NULL,                           /* do_ToolWindow */
   8192,                           /* do_StackSize */
};

/*
 *  The global error function
 */

static char *whoami;  /* global copy of argv[0] */

static void echo(const char *fmt, ...)
{
  va_list argp;
  va_start(argp,fmt);

  fprintf(stderr,"%s: ",whoami);
  vfprintf(stderr,(char *)fmt,argp);
  fprintf(stderr,"\n");
  fflush(stderr);

  va_end(argp);
}

/*
 *  Some top-level functions for ILBM loading
 */

static struct ILBMInfo *myloadbrush(char *fname)
{
  int err= 0;

  struct ILBMInfo *ilbm= (struct ILBMInfo *)AllocVec( sizeof(struct ILBMInfo), MEMF_CLEAR );

  if(ilbm)
  {
    /* ILBM Property chunks to be grabbed - only BMHD needed for this app */
    static LONG ilbmprops[] = { ID_ILBM, ID_BMHD, TAG_DONE };

    /* ILBM Collection chunks (more than one in file) to be gathered */
    static LONG *ilbmcollects = NULL;  /* none needed for this app */

    /* ILBM Chunk to stop on */
    static LONG ilbmstops[] = { ID_ILBM, ID_BODY, TAG_DONE };

    ilbm->ParseInfo.propchks    = ilbmprops;
    ilbm->ParseInfo.collectchks = ilbmcollects;
    ilbm->ParseInfo.stopchks    = ilbmstops;

    /* Alloc IFF handle for frame */

    if( (ilbm->ParseInfo.iff= AllocIFF()) )
    {
      if( (err= loadbrush(ilbm,fname)) )
      {
        /*fprintf(stderr,IFFerr(err));*/
        echo("Can't load ILBM `%s'",fname);
        ++err;
      }
    }
    else /* !AllocIFF() */
    {
      echo("AllocIFF() failed -- not enough memory!?");
      ++err;
    }
  }

  if(err && ilbm)
  {
    if(ilbm->ParseInfo.iff)
      FreeIFF(ilbm->ParseInfo.iff);

    FreeVec(ilbm);
    ilbm= (struct ILBMInfo *)NULL;
  }

  return ilbm;
}


static struct ILBMInfo *myunloadbrush(struct ILBMInfo *ilbm)
{
  if(ilbm)
  {
    unloadbrush(ilbm);

    if(ilbm->ParseInfo.iff)
      FreeIFF(ilbm->ParseInfo.iff);

    FreeVec(ilbm);
  }

  return (struct ILBMInfo *)0;
}


/**/

int main(int argc, char **argv)
{
  struct RDArgs *a;
  LONG args[17] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
  int rc= RETURN_OK;

  whoami= argv[0]; /* needed by echo() */

  if( (a= ReadArgs( /*  0 */ "FROM=NORMAL/K/A,"
                    /*  1 */ "SELECTED/K,"
                    /*  2 */ "IW=ICONWIDTH/K/N,"
                    /*  3 */ "IH=ICONHEIGHT/K/N,"
                    /*  4 */ "MINSIZE/S,"
                    /*  5 */ "TYPE/K,"
                    /*  6 */ "HIGHLIGHT/K,"
                    /*  7 */ "IX=ICONX/K/N,"
                    /*  8 */ "IY=ICONY/K/N,"
                    /*  9 */ "TOOLTYPES/K/M,"
                    /* 10 */ "STACKSIZE/K/N,"
                    /* 11 */ "DEFAULTTOOL/K,"
                    /* 12 */ "WX=WINDOWX/K/N,"
                    /* 13 */ "WY=WINDOWY/K/N,"
                    /* 14 */ "WW=WINDOWWIDTH/K/N,"
                    /* 15 */ "WH=WINDOWHEIGHT/K/N,"
                    /* 16 */ "TO/K/A", args, NULL )) )
  {
#if 0
    printf("NORMAL \"%s\"\n"
           "SELECTED \"%s\"\n"
           "ICONWIDTH=%ld ICONHEIGHT=%ld MINSIZE=%ld\n"
           "TYPE \"%s\"\n"
           "HIGHLIGHT \"%s\"\n"
           "ICONX=%ld ICONY=%ld\n"
           "STACKSIZE=%ld\n"
           "DEFAULTTOOL \"%s\"\n"
           "WINDOWX=%ld WINDOWY=%ld WINDOWWIDTH=%ld WINDOWHEIGHT=%ld\n"
           "TO \"%s\"\n"
      ,args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8]
      ,args[10],args[11],args[12],args[13],args[14],args[15],args[16]);
    {
      char **t= (char **)(args[9]);
      printf("TOOLTYPES"); while(t && *t) printf(" \"%s\"",*t++); printf("\n");
    }
#endif

    /* Open Libraries */

    if( (GfxBase = OpenLibrary(GRAPHICSNAME,0)) )
    {
      if( (IconBase= OpenLibrary(ICONNAME,36)) )
      {
        if( (IFFParseBase = OpenLibrary(IFFPARSENAME,0)) )
        {
          struct ILBMInfo *ilbm_normal, *ilbm_selected= (struct ILBMInfo *)NULL;

          if( (ilbm_normal= myloadbrush( (char *)(args[0]) )) )
          {
            if(args[1])
            {
              if(!(ilbm_selected= myloadbrush( (char *)(args[1]) )) )
                rc= RETURN_FAIL;
            }
          }
          else rc= RETURN_FAIL;

          /* IW=ICONWIDTH */

          if( rc == RETURN_OK )
          {
            WORD width;

            if(args[2])
              width= (WORD)(*((LONG *)(args[2])));

            else
            {
              if(ilbm_selected)
                 width= args[4] ? MIN(ilbm_normal->Bmhd.w, ilbm_selected->Bmhd.w)
                                : MAX(ilbm_normal->Bmhd.w, ilbm_selected->Bmhd.w);
              else
                 width= ilbm_normal->Bmhd.w;
            }

            icon.do_Gadget.Width = gr.Width = sr.Width = width;
          }

          /* IH=ICONHEIGHT */

          if( rc == RETURN_OK )
          {
            WORD height;

            if(args[3])
              height= (WORD)(*((LONG *)(args[3])));

            else
            {
              if(ilbm_selected)
                 height= args[4] ? MIN(ilbm_normal->Bmhd.h, ilbm_selected->Bmhd.h)
                                 : MAX(ilbm_normal->Bmhd.h, ilbm_selected->Bmhd.h);
              else
                 height= ilbm_normal->Bmhd.h;
            }

            icon.do_Gadget.Height = gr.Height = sr.Height = height;
          }

          /* TYPE */

          if( rc == RETURN_OK && args[5] )
          {
            int n= -1;
            char *s= (char *)args[5];

                 if( !stricmp(s,"DISK")    )   n= WBDISK;
            else if( !stricmp(s,"DRAWER")  )   n= WBDRAWER;
            else if( !stricmp(s,"TOOL")    )   n= WBTOOL;
            else if( !stricmp(s,"PROJECT") )   n= WBPROJECT;
            else if( !stricmp(s,"GARBAGE") )   n= WBGARBAGE;
            else if( !stricmp(s,"DEVICE")  )   n= WBDEVICE;
            else if( !stricmp(s,"KICK")    )   n= WBKICK;
            else if( !stricmp(s,"APPICON") )   n= WBAPPICON;

            if( n < 1 || n > 8 )
            {
              echo("Bad TYPE \"%s\" for template DISK/S,DRAWER/S,TOOL/S,PROJECT/S,GARBAGE/S",s);
              rc= RETURN_ERROR;
            }
            else icon.do_Type= (UBYTE)n;
          }

          /* HIGHLIGHT */

          if( rc == RETURN_OK && args[6] )
          {
            int n= -1;
            char *s= (char *)args[6];

                 if( !stricmp(s,"COMPLEMENT") )   n= GFLG_GADGHCOMP;
            else if( !stricmp(s,"BACKFILL")   )   n= GFLG_GADGHBOX;
            else if( !stricmp(s,"IMAGE")      )   n= GFLG_GADGHIMAGE;
            else if( !stricmp(s,"NONE")       )   n= GFLG_GADGHNONE;

            if( n < 0 )
            {
              echo("Bad HIGHLIGHT method \"%s\" for template COMPLEMENT/S,BACKFILL/S,IMAGE/S",s);
              rc= RETURN_ERROR;
            }
            else icon.do_Gadget.Flags= GFLG_GADGIMAGE | (UBYTE)n;

            if( ilbm_selected && n != GFLG_GADGHIMAGE )
            {
              echo("SELECTED image `%s' ignored for HIGHLIGHT medthod `%s'",args[1],s);
              ilbm_selected= myunloadbrush(ilbm_selected);
            }
            else if( !ilbm_selected && n == GFLG_GADGHIMAGE )
            {
              echo("You must specify a SELECTED image for HIGHLIGHT method `%s'",s);
              rc= RETURN_ERROR;
            }
          }

          /* IX=ICONX */

          if( rc == RETURN_OK && args[7] )
          {
            icon.do_Gadget.LeftEdge= (WORD)(*((LONG *)(args[7])));
          }

          /* IY=ICONY */

          if( rc == RETURN_OK && args[8] )
          {
            icon.do_Gadget.TopEdge= (WORD)(*((LONG *)(args[8])));
          }

          /* TOOLTYPES */

          if( rc == RETURN_OK && args[9] )
          {
            icon.do_ToolTypes= (char **)(args[9]);
          }

          /* STACKSIZE */

          if( rc == RETURN_OK && args[10] )
          {
            icon.do_StackSize= (*((LONG *)(args[10])));
          }

          /* DEFAULTTOOL */

          if( rc == RETURN_OK && args[11] )
          {
            icon.do_DefaultTool= (char *)(args[11]);
          }

          /* WX=WINDOWX */

          if( rc == RETURN_OK && args[12] )
          {
            dd.dd_NewWindow.LeftEdge= (WORD)(*((LONG *)(args[12])));
          }

          /* WY=WINDOWY */

          if( rc == RETURN_OK && args[13] )
          {
            dd.dd_NewWindow.TopEdge= (WORD)(*((LONG *)(args[13])));
          }

          /* WW=WINDOWWIDTH */

          if( rc == RETURN_OK && args[14] )
          {
            dd.dd_NewWindow.Width= (WORD)(*((LONG *)(args[14])));
          }

          /* WH=WINDOWHEIGHT */

          if( rc == RETURN_OK && args[15] )
          {
            dd.dd_NewWindow.Height= (WORD)(*((LONG *)(args[15])));
          }

          /*
           *  Postwork
           */

          if( rc == RETURN_OK )
          {
            if(icon.do_Type != WBDRAWER && icon.do_Type != WBDISK)
              icon.do_DrawerData= (struct DrawerData *)NULL;

            if(!(icon.do_Gadget.Flags &~ GFLG_GADGHIMAGE))
            {
              icon.do_Gadget.SelectRender= (struct Image *)NULL;

              if(ilbm_selected)
                ilbm_selected= myunloadbrush(ilbm_selected);
            }
            else if(!ilbm_selected)
            {
              icon.do_Gadget.SelectRender= (struct Image *)NULL;
              icon.do_Gadget.Flags= (icon.do_Gadget.Flags & ~GFLG_GADGHIMAGE) | GFLG_GADGHCOMP;
            }
          }

          /*
           *  Create the icon and save it
           */

          if( rc == RETURN_OK )
          {
            WORD width  = icon.do_Gadget.Width;
            WORD height = icon.do_Gadget.Height;

            UWORD *gr_data, *sr_data= (UWORD *)NULL;

            if( (gr_data= ImageDataFromBitMap(ilbm_normal->brbitmap, width, height)) )
            {
              UBYTE pp[]= { 0,1,3,7,15,31,63,127,255 };  /* PlanePick lookup table */

              gr.ImageData = gr_data;
              gr.Depth     = ilbm_normal->brbitmap->Depth;
              gr.PlanePick = pp[ilbm_normal->brbitmap->Depth];

              if(ilbm_selected)
              {
                if( (sr_data= ImageDataFromBitMap(ilbm_selected->brbitmap, width, height)) )
                {
                  sr.ImageData = sr_data;
                  sr.Depth     = ilbm_selected->brbitmap->Depth;
                  sr.PlanePick = pp[ilbm_selected->brbitmap->Depth];
                }
                else /* !sr_data */
                {
                  echo("ImageDataFromBitMap() failed -- not enough memory!?");
                  rc= ERROR_NO_FREE_STORE;
                }
              }

              if( rc == RETURN_OK )
              {
                if( !PutDiskObject((char *)(args[16]),&icon) )
                  PrintFault(rc= IoErr(),(char *)(args[16]));
              }

              if(sr_data)
                FreeVec(sr_data);

              FreeVec(gr_data);
            }
            else /* !gr_data */
            {
              echo("ImageDataFromBitMap() failed -- not enough memory!");
              rc= ERROR_NO_FREE_STORE;
            }
          }

          ilbm_normal   = myunloadbrush( ilbm_normal   );
          ilbm_selected = myunloadbrush( ilbm_selected );

          CloseLibrary(IFFParseBase);
        }
        else
        {
          echo("No %s",IFFPARSENAME);
          rc= RETURN_FAIL;
        }

        CloseLibrary(IconBase);
      }
      else
      {
        echo("No %s",ICONNAME);
        rc= RETURN_FAIL;
      }

      CloseLibrary(GfxBase);
    }
    else
    {
      echo("No %s",GRAPHICSNAME);
      rc= RETURN_FAIL;
    }

    FreeArgs(a);
  }
  else /* !ReadArgs */
  {
    if(argc == 1)
      display_version_information();

    else
      PrintFault(rc= IoErr(), NULL);
  }

  return rc;
}



/* written 1993 by Tobias Ferber,  All Rights Reserved */

UWORD *ImageDataFromBitMap(struct BitMap *bm, WORD width, WORD height)
{
  ULONG bpr = ((width+15)/16) * 2;
  UBYTE *idata= (UBYTE *)AllocVec( bpr * height * bm->Depth, MEMF_CHIP|MEMF_CLEAR );

  /*printf("ImageDataFromBitMap(): width=%d,height=%d,depth=%d,bpr=%ld\n",width,height,bm->Depth,bpr);*/

  if(idata)
  {
    int p,b,r;

    int P= bm->Depth;
    int B= MIN(bm->BytesPerRow, bpr);
    int R= MIN(bm->Rows, height);

    for(p=0; p<P; p++)
    {
      UBYTE *src= (UBYTE *)(bm->Planes[p]);
      UBYTE *dst= (UBYTE *)&idata[p*bpr*height];

      for(r=0; r<R; r++)
      {
        /* save "beginning of line" values */
        UBYTE *_src= src; 
        UBYTE *_dst= dst;


        for(b=0; b<B; b++)
          *dst++ = *src++;

        /* jump to the next line */
        src= &_src[ bm->BytesPerRow ];
        dst= &_dst[ bpr ];
      }
    }
  }

  return (UWORD *)idata;
}
