#include <clib/alib_protos.h>
#include <pragma/datatypes_lib.h>
#include <pragma/dos_lib.h>
#include <pragma/exec_lib.h>
#include <pragma/intuition_lib.h>
#include <pragma/graphics_lib.h>
#include <pragma/utility_lib.h>
#include <datatypes/pictureclass.h>
#include <exec/memory.h>
#include <intuition/icclass.h>
#include <stdlib.h>
#include <string.h>

static long ReadPrefs()
{
long ret=2;
BPTR fh;
if(fh=Open("ENV:DataTypes/pcd.prefs",MODE_OLDFILE))
	{
	char text[20];
	if(FGets(fh,text,20))
		{
		ret=atol(text);
		if(ret<0) ret=0;
		else if(ret>5) ret=5;
		}
	Close(fh);
	}
return ret;
}

ULONG Colors2DT(Object *obj,UBYTE *color)
{
UBYTE *cr;
ULONG *cregs,i,num,error=0;
GetDTAttrs(obj,PDTA_NumColors,&num,PDTA_ColorRegisters,&cr,PDTA_CRegs,&cregs,TAG_END);
if(cr&&cregs)
	{
	for(i=0;i<num;i++,cr+=3,cregs+=3,color+=4)
		{
		cr[0]=color[1];
		cr[1]=color[2];
		cr[2]=color[3];
		cregs[0]=cr[0]<<24;
		cregs[1]=cr[1]<<24;
		cregs[2]=cr[2]<<24;
		}
	}
else error=ERROR_NO_FREE_STORE;
return error;
}

static ULONG ReadP6_V43(Object *obj,BitMapHeader *bh,BPTR file)
{
ULONG error=0,len=bh->bmh_Width*bh->bmh_Height*3;
UBYTE *pix;
if(pix=(UBYTE *)AllocVec(len,0))
	{
	if(Read(file,pix,len)==len) DoMethod(obj,PDTM_WRITEPIXELARRAY,pix,PBPAFMT_RGB,bh->bmh_Width*3,0,0,bh->bmh_Width,bh->bmh_Height);
	else error=DTERROR_NOT_ENOUGH_DATA;
	FreeVec(pix);
	}
else if(pix=(UBYTE *)AllocVec(bh->bmh_Width*3,0))
	{
	UWORD y;
	for(y=0;y<bh->bmh_Height;y++)
		{
		if(Read(file,pix,bh->bmh_Width*3)!=bh->bmh_Width*3)
			{
			error=DTERROR_NOT_ENOUGH_DATA;
			break;
			}
		DoMethod(obj,PDTM_WRITEPIXELARRAY,pix,PBPAFMT_RGB,bh->bmh_Width*3,0,y,bh->bmh_Width,1);
		}
	FreeVec(pix);
	}
else error=ERROR_NO_FREE_STORE;
return error;
}

static ULONG ReadNum(BPTR file)
{
ULONG retval=0;
for(;;)
	{
	char c;
	if(Read(file,&c,1)!=1) return 0;
	if(c==10||c==32) break;
	retval*=10;
	retval+=c-'0';
	}
return retval;
}

static void tmpname(char *buf)
{
DateStamp ds;
SPrintf(buf,"PIPE:%08lx%08lx%08lx%08lx",FindTask(0),ds.ds_Days,ds.ds_Minute,ds.ds_Tick);
}

static ULONG GetPicture(IClass *cl,Object *obj)
{
ULONG error=0;
BPTR nil;
if(nil=Open("NIL:",MODE_OLDFILE))
	{
	long res;
	char *dname;
	res=ReadPrefs();
	GetDTAttrs(obj,DTA_Name,&dname,TAG_END);
	if(dname)
		{
		SetDTAttrs(obj,0,0,DTA_ObjName,dname,TAG_END);
		char *tmp;
		if(tmp=(char *)AllocVec(40,0))
			{
			char *fname;
			tmpname(tmp);
			if(fname=(char *)AllocVec(strlen(dname)+100,0))
				{
				SPrintf(fname,"run pcdtoppm >%s -%lu -ppm \"%s%\"",tmp,res+1,dname);
				if(Execute(fname,nil,nil)!=DOSFALSE)
					{
					BPTR file;
					if(file=Open(tmp,MODE_OLDFILE))
						{
						BitMapHeader *bh;
						char head[3];
						GetDTAttrs(obj,PDTA_BitMapHeader,&bh,TAG_END);
						if(bh)
							{
							if(Read(file,head,3)==3)
								{
								bh->bmh_Width=ReadNum(file);
								bh->bmh_PageWidth=bh->bmh_Width;
								bh->bmh_Height=ReadNum(file);
								bh->bmh_PageHeight=bh->bmh_Height;
								bh->bmh_Compression=1;
								ReadNum(file);
								bh->bmh_Depth=24;
								SetDTAttrs(obj,0,0,DTA_ErrorNumber,&error,DTA_NominalHoriz,bh->bmh_Width,DTA_NominalVert,bh->bmh_Height,PDTA_ModeID,0,PDTA_SourceMode,PMODE_V43,TAG_END);
								if(!error) error=ReadP6_V43(obj,bh,file);
								}
							else error=DTERROR_NOT_ENOUGH_DATA;
							}
						else error=ERROR_NO_FREE_STORE;
						Close(file);
						}
					else error=IoErr();
					}
				else error=IoErr();
				FreeVec(fname);
				}
			else error=ERROR_NO_FREE_STORE;
			FreeVec(tmp);
			}
		else error=ERROR_NO_FREE_STORE;
		}
	else error=ERROR_NO_FREE_STORE;
	Close(nil);
	}
else error=IoErr();
return error;
}

static ULONG mNew(IClass *cl,Object *obj,opSet *msg)
{
TagItem *ti;
if(ti=FindTagItem(DTA_SourceType,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(IClass *cl,Object *obj,opSet *msg)
{
ULONG retval;
if(retval=DoSuperMethodA(cl,obj,Msg(msg)))
	{
	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 IClass *cl,register __a2 Object *obj,register __a1 Msg msg)
{
ULONG retval;
switch(msg->MethodID)
	{
	case OM_NEW:
		retval=mNew(cl,obj,(opSet *)msg);
		break;
	case OM_UPDATE:
		if(DoMethod(obj,ICM_CHECKLOOP)) break;
	case OM_SET:
		retval=mSet(cl,obj,(opSet *)msg);
		break;
	default:
		retval=DoSuperMethodA(cl,obj,msg);
		}
return retval;
}
