#include <clib/alib_protos.h>
#include <clib/cybergraphics_protos.h>
#include <clib/datatypes_protos.h>
#include <clib/exec_protos.h>
#include <clib/graphics_protos.h>
#include <clib/iffparse_protos.h>
#include <clib/intuition_protos.h>
#include <clib/xpkmaster_protos.h>
#include <datatypes/datatypesclass.h>
#include <datatypes/pictureclass.h>
#include <exec/memory.h>
//#include <libraries/rgfx.h>
#include "class.h"
#include "rgfx.h"

extern Library *CyberGfxBase;

void ReadPrefs(Data *data);

static BOOL PutRGHD(IFFHandle *iff,RGHD *rh)
{
BOOL ret=0;
if(!PushChunk(iff,0,ID_RGHD,sizeof(RGHD)))
	{
	if(WriteChunkRecords(iff,rh,sizeof(RGHD),1)==1)
		{
		if(!PopChunk(iff)) ret=1;
		}
	}
return ret;
}

static BOOL PutRCOL(Object *obj,IFFHandle *iff)
{
BOOL ret=0;
if(!PushChunk(iff,0,ID_RCOL,sizeof(RCOL)))
	{
	RCOL *rc;
	if(rc=(RCOL *)AllocVec(sizeof(RCOL),MEMF_CLEAR))
		{
		ULONG i,n,*cr;
		GetDTAttrs(obj,PDTA_NumColors,&n,PDTA_CRegs,&cr,TAG_END);
		for(i=0;i<n;i++)
			{
			UWORD j;
			for(j=0;j<3;j++) rc->rcol_Colors[i][j]=*(cr++)>>24;
			}
		if(WriteChunkRecords(iff,rc,sizeof(RCOL),1)==1)
			{
			if(!PopChunk(iff)) ret=1;
			}
		FreeVec(rc);
		}
	}
return ret;
}

static BOOL PutRSCM(Object *obj,IFFHandle *iff,RGHD *rh)
{
BOOL ret=0;
if(!PushChunk(iff,0,ID_RSCM,sizeof(RSCM)))
	{
	ULONG mode;
	RSCM rs={INVALID_ID,INVALID_ID,INVALID_ID};
	GetDTAttrs(obj,PDTA_ModeID,&mode,TAG_END);
	if(CyberGfxBase&&IsCyberModeID(mode))
		{
		rs.rscm_CGfx=mode;
		if(rh->rgfx_Depth<=8) rs.rscm_AGA=BestModeID(
		BIDTAG_NominalWidth,rh->rgfx_PageWidth,BIDTAG_NominalHeight,rh->rgfx_PageHeight,
		BIDTAG_DesiredWidth,rh->rgfx_Width,BIDTAG_DesiredHeight,rh->rgfx_Height,
		BIDTAG_Depth,rh->rgfx_Depth,BIDTAG_MonitorID,DEFAULT_MONITOR_ID,
      BIDTAG_DIPFMustNotHave,DIPF_IS_DUALPF|DIPF_IS_PF2PRI|DIPF_IS_HAM|DIPF_IS_EXTRAHALFBRITE,TAG_END);
		}
	else
		{
		rs.rscm_AGA=mode;
		if(!(mode&(HAM_KEY|EXTRAHALFBRITE_KEY|LORESDPF_KEY)))
			{
			if(CyberGfxBase) rs.rscm_CGfx=BestCModeIDTags(CYBRBIDTG_NominalWidth,rh->rgfx_Width,CYBRBIDTG_NominalHeight,rh->rgfx_Height,CYBRBIDTG_Depth,rh->rgfx_Depth,TAG_END);
			}
		}
	if(WriteChunkRecords(iff,&rs,sizeof(RSCM),1)==1)
		{
		if(!PopChunk(iff)) ret=1;
		}
	}
return ret;
}

static BOOL WriteChunky_XPK(Object *obj,IFFHandle *iff,RGHD *rh,BitMap *bm,Data *data)
{
BOOL ret=0;
ULONG len=rh->rgfx_Width*rh->rgfx_Height;
UBYTE *mem;
if(mem=(UBYTE *)AllocVec(len,0))
	{
	UBYTE *pix;
	if(pix=(UBYTE *)AllocVec(((rh->rgfx_Width+16)>>4)<<4,0))
		{
		BitMap *tbm;
		if(tbm=AllocBitMap(rh->rgfx_Width,1,rh->rgfx_Depth,0,bm))
			{
			ULONG y,xpklen,outlen;
			UBYTE *xpk=mem;
			RastPort rp,trp;
			InitRastPort(&rp);
			InitRastPort(&trp);
			rp.BitMap=bm;
			trp.BitMap=tbm;
			for(y=0;y<rh->rgfx_Height;y++,xpk+=rh->rgfx_Width)
				{
				ReadPixelLine8(&rp,0,y,rh->rgfx_Width,pix,&trp);
				CopyMem(pix,xpk,rh->rgfx_Width);
				}
			if(!XpkPackTags(XPK_InBuf,mem,XPK_InLen,len,XPK_GetOutBuf,&xpk,XPK_GetOutBufLen,&xpklen,XPK_GetOutLen,&outlen,XPK_PackMethod,data->xpk,XPK_PackMode,data->xpkmode,XPK_Password,data->password,TAG_END))
				{
				if(WriteChunkRecords(iff,xpk,outlen,1)==1) ret=1;
				FreeMem(xpk,xpklen);
				}
			FreeBitMap(tbm);
			}
		FreeVec(pix);
		}
	FreeVec(mem);
	}
return ret;
}

static BOOL Write24_XPK(Object *obj,IFFHandle *iff,RGHD *rh,Data *data)
{
BOOL ret=0;
UBYTE *pix;
ULONG len=rh->rgfx_BytesPerLine*rh->rgfx_Height;
if(pix=(UBYTE *)AllocVec(len,0))
	{
	ULONG xpklen,outlen;
	UBYTE *xpk;
	DoMethod(obj,PDTM_READPIXELARRAY,pix,RECTFMT_RGB,rh->rgfx_BytesPerLine,0,0,rh->rgfx_Width,rh->rgfx_Height);
	if(!XpkPackTags(XPK_InBuf,pix,XPK_InLen,len,XPK_GetOutBuf,&xpk,XPK_GetOutBufLen,&xpklen,XPK_GetOutLen,&outlen,XPK_PackMethod,data->xpk,XPK_PackMode,data->xpkmode,XPK_Password,data->password,TAG_END))
		{
		if(WriteChunkRecords(iff,xpk,outlen,1)==1) ret=1;
		FreeMem(xpk,xpklen);
		}
	FreeVec(pix);
	}
return ret;
}

static BOOL PutBODY(IClass *cl,Object *obj,IFFHandle *iff,RGHD *rh)
{
BOOL ret=0;
if(!PushChunk(iff,0,ID_RBOD,IFFSIZE_UNKNOWN))
	{
	BOOL wok=0;
	BitMap *bm;
	Data *data=(Data *)INST_DATA(cl,obj);
	ReadPrefs(data);
	GetDTAttrs(obj,PDTA_BitMap,&bm,TAG_END);
	if(rh->rgfx_Depth>8) wok=Write24_XPK(obj,iff,rh,data);
	else wok=WriteChunky_XPK(obj,iff,rh,bm,data);
	if(wok)
		{
		if(!PopChunk(iff)) ret=1;
		}
	}
return ret;
}

ULONG SaveRGFX(IClass *cl,Object *obj,dtWrite *msg)
{
ULONG retval=0;
IFFHandle *iff;
SignalSemaphore *lock=((DTSpecialInfo *)((Gadget *)obj)->SpecialInfo);
ObtainSemaphoreShared(lock);
if(iff=AllocIFF())
	{
	iff->iff_Stream=msg->dtw_FileHandle;
	InitIFFasDOS(iff);
	if(!OpenIFF(iff,IFFF_WRITE))
		{
		if(!PushChunk(iff,ID_RGFX,ID_FORM,IFFSIZE_UNKNOWN))
			{
			BOOL ok=0;
			BitMapHeader *bh;
			RGHD rh;
			GetDTAttrs(obj,PDTA_BitMapHeader,&bh,TAG_END);
			rh.rgfx_LeftEdge=bh->bmh_Left;
			rh.rgfx_TopEdge=bh->bmh_Top;
			rh.rgfx_Width=bh->bmh_Width;
			rh.rgfx_Height=bh->bmh_Height;
			rh.rgfx_PageWidth=bh->bmh_PageWidth;
			rh.rgfx_PageHeight=bh->bmh_PageHeight;
			rh.rgfx_Depth=bh->bmh_Depth;
			if(rh.rgfx_Depth<=8)
				{
				rh.rgfx_PixelBits=8;
				rh.rgfx_BytesPerLine=rh.rgfx_Width;
				rh.rgfx_BitMapType=RMBT_BYTECHUNKY8;
				}
			else
				{
				rh.rgfx_PixelBits=24;
				rh.rgfx_BytesPerLine=rh.rgfx_Width*3;
				rh.rgfx_BitMapType=RMBT_3BYTERGB24;
				}
			rh.rgfx_Compression=RCMT_XPK;
			rh.rgfx_XAspect=bh->bmh_XAspect;
			rh.rgfx_YAspect=bh->bmh_YAspect;
			if(PutRGHD(iff,&rh))
				{
				if(bh->bmh_Depth>8||PutRCOL(obj,iff))
					{
					if(PutRSCM(obj,iff,&rh)) ok=PutBODY(cl,obj,iff,&rh);
					}
				}
			if(ok)
				{
				if(PopChunk(iff)) ok=0;
				else retval=1;
				}
			}
		CloseIFF(iff);
		}
	FreeIFF(iff);
	}
ReleaseSemaphore(lock);
return retval;
}

