#include <clib/alib_protos.h>
#include <pragma/datatypes_lib.h>
#include <pragma/dos_lib.h>
#include <pragma/exec_lib.h>
#include <pragma/graphics_lib.h>
#include <pragma/intuition_lib.h>
#include <pragma/utility_lib.h>
#include <datatypes/pictureclass.h>
#include <intuition/icclass.h>
#include <setjmp.h>
#include "gif.h"

extern struct Library *SuperClassBase;
extern struct Library *GfxBase;

ULONG GetPicturePPC(Object *obj,BPTR file,struct BitMapHeader *bh);

static ULONG GetPicture(struct IClass *cl,Object *obj)
{
ULONG error=0;
long err;
BPTR file;
struct BitMapHeader *bh;
GetDTAttrs(obj,DTA_Name,&bh,TAG_END);
if(bh) SetDTAttrs(obj,0,0,DTA_ObjName,bh,TAG_END);
GetDTAttrs(obj,DTA_Handle,&file,PDTA_BitMapHeader,&bh,TAG_END);
if(bh)
	{
	if(!file)
		{
		GetDTAttrs(obj,DTA_SourceType,&err,TAG_END);
		if(err!=DTST_RAM) return ERROR_REQUIRED_ARG_MISSING;
		else return 0;
		}
	error=GetPicturePPC(obj,file,bh);
	}
else error=ERROR_NO_FREE_STORE;
return error;
}

void write_gif(struct GIF *gif)
{
if(SuperClassBase->lib_Version>=43) DoMethod(gif->obj,PDTM_WRITEPIXELARRAY,gif->buffer,PBPAFMT_LUT8,gif->image_width,0,0,gif->image_width,gif->image_height);
else
	{
	struct RastPort rp;
	InitRastPort(&rp);
	rp.BitMap=gif->bm;
	if(GfxBase->lib_Version>=40) WriteChunkyPixels(&rp,0,0,gif->image_width-1,gif->image_height-1,gif->buffer,gif->image_width);
	else
		{
		BitMap *tbm;
		if(tbm=AllocBitMap(gif->image_width,1,gif->depth,BMF_MINPLANES,0))
			{
			ULONG y;
			struct RastPort trp;
			InitRastPort(&trp);
			trp.BitMap=tbm;
			for(y=0;y<gif->image_height;y++) WritePixelLine8(&rp,0,y,gif->image_width,gif->buffer+y*gif->image_width,&trp);
			FreeBitMap(tbm);
			}
		}
	}
}

static ULONG mNew(struct IClass *cl,Object *obj,struct opSet *msg)
{
struct TagItem *ti;
if(ti=FindTagItem(DTA_SourceType,(((struct opSet *)msg)->ops_AttrList)))
	{
	if(ti->ti_Data!=DTST_FILE&&ti->ti_Data!=DTST_CLIPBOARD&&ti->ti_Data!=DTST_RAM)
		{
		SetIoErr(ERROR_OBJECT_WRONG_TYPE);
		return 0;
		}
	}
if(obj==(Object *)cl)
	{
	if(obj=(Object *)DoSuperMethodA(cl,obj,Msg(msg)))
		{
		ULONG error;
		if(error=GetPicture(cl,obj))
			{
			SetIoErr(error);
			CoerceMethod(cl,obj,OM_DISPOSE);
			obj=0;
			}
		}
	}
else
	{
	SetIoErr(ERROR_NOT_IMPLEMENTED);
	obj=0;
	}
return ULONG(obj);
}

static ULONG mSet(struct IClass *cl,Object *obj,struct opSet *msg)
{
ULONG retval;
if(retval=DoSuperMethodA(cl,obj,Msg(msg)))
	{
	struct RastPort *rp;
	if(rp=ObtainGIRPort(msg->ops_GInfo))
		{
		DoMethod(obj,GM_RENDER,msg->ops_GInfo,rp,GREDRAW_UPDATE);
		ReleaseGIRPort(rp);
		retval=0;
		}
	}
return retval;
}

extern "C" ULONG Dispatcher(register __a0 struct IClass *cl,register __a2 Object *obj,register __a1 Msg msg)
{
ULONG retval;
switch(msg->MethodID)
	{
	case OM_NEW:
		retval=mNew(cl,obj,(struct opSet *)msg);
		break;
	case OM_UPDATE:
		if(DoMethod(obj,ICM_CHECKLOOP)) break;
	case OM_SET:
		retval=mSet(cl,obj,(struct opSet *)msg);
		break;
	default:
		retval=DoSuperMethodA(cl,obj,msg);
		}
return retval;
}
