/*
**      $VER: libfuncs.h 40.3 (13.9.96)
**
**      datatype functions
**
**      (C) Copyright 1996 Andreas R. Kleinert
**      All Rights Reserved.
*/

#define __USE_SYSBASE

#ifndef EXEC_TYPES_H
#include <exec/types.h>
#endif /* EXEC_TYPES_H */

#ifndef EXEC_MEMORY_H
#include <exec/memory.h>
#endif /* EXEC_MEMORY_H */

#ifndef GRAPHICS_GFXBASE_H
#include <graphics/gfxbase.h>
#endif /* GRAPHICS_GFXBASE_H */

#ifndef GRAPHICS_VIEW_H
#include <graphics/view.h>
#endif /* GRAPHICS_VIEW_H */

#include <datatypes/pictureclass.h>

#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/intuition.h>
#include <proto/graphics.h>
#include <proto/utility.h>
#include <proto/datatypes.h>

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

#include <class/classbase.h>
#include "libfuncs.h"


Class * __saveds __asm ObtainPicClass ( register __a6 struct ClassBase *cb)
{
 return (cb->cb_Class);
}

ULONG setdtattrs (struct ClassBase * cb, Object * o, ULONG data,...)
{
 return (SetDTAttrsA (o, NULL, NULL, (struct TagItem *) & data));
}

ULONG getdtattrs (struct ClassBase * cb, Object * o, ULONG data,...)
{
 return (GetDTAttrsA (o, (struct TagItem *) & data));
}


extern char __aligned ExLibName [];

Class *initClass (struct ClassBase * cb)
{
 Class *cl;

 if (cl = MakeClass (&ExLibName[0], PICTUREDTCLASS, NULL, NULL, 0L))
  {
   cl->cl_Dispatcher.h_Entry = (HOOKFUNC) Dispatch;
   cl->cl_UserData = (ULONG) cb;
   AddClass (cl);
  }

 return (cl);
}

ULONG __saveds __asm Dispatch ( register __a0 Class * cl, register __a2 Object * o, register __a1 Msg msg)
{
 struct ClassBase *cb = (struct ClassBase *) cl->cl_UserData;
 ULONG retval;

 switch (msg->MethodID)
  {
   case OM_NEW:
    {
     if (retval = DoSuperMethodA (cl, o, msg))
      {
       if (!GetGfxData (cb, cl, (Object *) retval, ((struct opSet *) msg)->ops_AttrList))
        {
         CoerceMethod (cl, (Object *) retval, OM_DISPOSE);

	 return(NULL);
        }
      }
     break;
    }
   default:
    {
     retval = (ULONG) DoSuperMethodA (cl, o, msg);
     break;
    }
  }

 return (retval);
}

ULONG __saveds __asm GetGfxData ( register __a6 struct ClassBase * cb, register __a0 Class * cl, register __a2 Object * o, register __a1 struct TagItem * attrs)
{
 return( DTS_ReadIntoBitMap(cb, o, attrs) );
}

ULONG __saveds __stdargs dt_GetBestModeID(ULONG width, ULONG height, ULONG depth);
void __saveds __stdargs DTS_SkipComment(BPTR handle, UBYTE *buf, ULONG *cnt);

ULONG __saveds __stdargs DTS_ReadIntoBitMap(struct ClassBase *cb, Object * o, struct TagItem * attrs)
{
 struct BitMapHeader *bmhd;

 BOOL success = TRUE;

 struct RastPort __aligned trp;
 struct RastPort __aligned rp;

 struct BitMap *bm, *tbm;

 ULONG i, width, height, depth, maxval;

 UBYTE *readname, *buffer;

 struct ColorRegister *cmap;
 LONG *cregs;

 BPTR fh;

 UBYTE wstr[16], hstr[16], dstr[16];
 UWORD ID;


 readname = (UBYTE *) GetTagData (DTA_Name, NULL, attrs);
 getdtattrs (cb, o, PDTA_BitMapHeader, &bmhd, TAG_DONE, NULL);


 fh = Open(readname, MODE_OLDFILE);
 if(!fh) return(FALSE);


 FRead(fh, &ID, 2, 1);
 FRead(fh, &wstr[0], 1, 1); /* filter CR */


 /* get Width */

 for(i=0; i<16; i++)
  {
   if(!FRead(fh, &wstr[i], 1, 1))
    {
     Close(fh);
     return(FALSE);
    }

   if(  wstr[i]=='#') DTS_SkipComment(fh, wstr, &i);
   if( (wstr[i]==' ') || (wstr[i]==0xa) || (wstr[i]==13) )
    {
     wstr[i] = (UBYTE) '\0';
     break;
    }
  }
 
 /* get Height */

 for(i=0; i<16; i++)
  {
   if(!FRead(fh, &hstr[i], 1, 1))
    {
     Close(fh);
     return(FALSE);
    }

   if(  hstr[i]=='#') DTS_SkipComment(fh, hstr, &i);
   if( (hstr[i]==' ') || (hstr[i]==0xa) || (hstr[i]==13) )
    {
     hstr[i] = (UBYTE) '\0';
     break;
    }
  }

 /* Maxval */

 for(i=0; i<16; i++)
  {
   if(!FRead(fh, &dstr[i], 1, 1))
    {
     Close(fh);
     return(FALSE);
    }

   if(  dstr[i]=='#') DTS_SkipComment(fh, dstr, &i);
   if( (dstr[i]==' ') || (dstr[i]==0xa) || (dstr[i]==13) )
    {
     dstr[i] = (UBYTE) '\0';
     break;
    }
  }

 width  = (ULONG) atol(wstr);
 height = (ULONG) atol(hstr);
 maxval = (ULONG) atol(dstr);
 if(maxval > 255)
  {
   Close(fh);
   return(FALSE);
  }

 bmhd->bmh_Width  = (bmhd->bmh_PageWidth  = width);
 bmhd->bmh_Height = (bmhd->bmh_PageHeight = height);
 depth            = (bmhd->bmh_Depth = 8);

 setdtattrs(cb, o, PDTA_NumColors,      256,
                   TAG_DONE,            NULL);

 getdtattrs(cb, o, PDTA_ColorRegisters, (ULONG) &cmap,
                   PDTA_CRegs,	        &cregs,
                   TAG_DONE,            NULL);

 if( (!cmap) || (!cregs) )
  {
   success = FALSE;
  }else
  {
   if(tbm = AllocBitMap (bmhd->bmh_Width, 1, bmhd->bmh_Depth, BMF_CLEAR, NULL))
    {
     InitRastPort (&trp);
     trp.BitMap = tbm;

     if (bm = AllocBitMap (bmhd->bmh_Width, bmhd->bmh_Height, bmhd->bmh_Depth, BMF_CLEAR, NULL))
      {
       InitRastPort (&rp);
       rp.BitMap = bm;

       buffer = (APTR) AllocVec(width + 1024, MEMF_CLEAR|MEMF_PUBLIC);
       if(buffer)
        {
         for(i=0; i<height; i++)
          {
           FRead(fh, buffer, width, 1);

           WritePixelLine8(&rp, 0, i, width, buffer, &trp);
          }

         for(i=0; i<maxval; i++)
          {
           cmap->red   = i * (256 / maxval);
           cmap->green = i * (256 / maxval);
           cmap->blue  = i * (256 / maxval);
           cmap++;

           cregs[i * 3    ] = ((LONG)i * (256 / maxval))<<24;
           cregs[i * 3 + 1] = ((LONG)i * (256 / maxval))<<24;
           cregs[i * 3 + 2] = ((LONG)i * (256 / maxval))<<24;
          }

         cmap->red   = 255;
         cmap->green = 255;
         cmap->blue  = 255;
         cmap++;

         cregs[i * 3    ] = ((LONG)255)<<24;
         cregs[i * 3 + 1] = ((LONG)255)<<24;
         cregs[i * 3 + 2] = ((LONG)255)<<24;

         setdtattrs (cb, o,
	             DTA_ObjName,	readname,
		     DTA_NominalHoriz,	bmhd->bmh_Width,
		     DTA_NominalVert,	bmhd->bmh_Height,
		     PDTA_BitMap,	bm,
		     PDTA_ModeID,	dt_GetBestModeID(bmhd->bmh_Width, bmhd->bmh_Height, 8),
		     TAG_DONE);

         FreeVec(buffer);
        }else
        {
         success = FALSE;
         SetIoErr (ERROR_NO_FREE_STORE);
        }
      }else
      {
       success = FALSE;
       SetIoErr (ERROR_NO_FREE_STORE);
      }

     FreeBitMap(tbm);
    }else
    {
     success = FALSE;
     SetIoErr (ERROR_NO_FREE_STORE);
    }
  }

 Close(fh);

 return(success);
}

ULONG __saveds __stdargs dt_GetBestModeID(ULONG width, ULONG height, ULONG depth)
{
 ULONG mode_id = NULL;

 mode_id = BestModeID(BIDTAG_NominalWidth,  width,
                      BIDTAG_NominalHeight, height,
                      BIDTAG_DesiredWidth,  width,
                      BIDTAG_DesiredHeight, height,
                      BIDTAG_Depth,         depth,
                      TAG_END);

 if(!mode_id) /* BestModeID failed */
  {
   /* Uses OverScan values for checking. */
   /* Assumes an ECS-System.             */

        if(width > 724 && depth < 3)   mode_id = SUPER_KEY;
   else if(width > 362 && depth < 5)   mode_id = HIRES_KEY;
   else                                mode_id = LORES_KEY;

   if(!ModeNotAvailable(mode_id | PAL_MONITOR_ID))    /* for PAL  Systems */
    {
     if(height > 283) mode_id |= LACE;

     mode_id |= PAL_MONITOR_ID;
    }else
    {
     if(!ModeNotAvailable(mode_id | NTSC_MONITOR_ID)) /* for NTSC Systems */
      {
       if(height > 241) mode_id |= LACE;

       mode_id |= NTSC_MONITOR_ID;
      }
    }
  }

 if(!(mode_id & 0xFFFF0000))
  {
         if(!ModeNotAvailable(mode_id |  PAL_MONITOR_ID)) mode_id |=  PAL_MONITOR_ID;
    else if(!ModeNotAvailable(mode_id | NTSC_MONITOR_ID)) mode_id |= NTSC_MONITOR_ID;
  }

 if(mode_id == INVALID_ID) mode_id = NULL;

 return(mode_id);
}

void __saveds __stdargs DTS_SkipComment(BPTR handle, UBYTE *buf, ULONG *cnt)
{
 do
  {
   FRead(handle, buf, 1, 1);
  } while( (*buf!=0xa) && (*buf!=13) );

 FRead(handle, buf, 1, 1);

 *cnt = (LONG) 0;
}
