#include "cii.h"
#include "cii←matrix.h"

#ifdef DEBUG
#define CHK(x) {res=x; if (CII←RES←ok!=res) (*((CII←RES*)1)) = (res);}
        /* debugging CHK intentionally crashes if there is an error */
#else
#define CHK(x) {res=x; if (CII←RES←ok!=res) return(res);}
#endif
extern void run←ciiicecream(CII←Handle h);

static CII←RectangleRep rect1 = {0.0, 0.0, 1000.0, 1000.0};

static CII←RES
graywedge(CII←Handle h)
{
	CII←RES res = CII←RES←ok;
	CII←RectangleRep rect = {0.0, 0.0, 1.0, 100.0};
	int i;
	
	i = 0;
	while (i < 100) {
		float g;
		rect.x = i;
		g = i / 99.0;
		CHK(CII←SetGray(h, &g));
		CHK(CII←MaskRectangle(h, &rect));
		i = i + 1;
	};
	return(res);
}

static long*
WordPointer(unsigned char * charP)
{
	long unsigned w;
	long unsigned d;
	d = sizeof(long);
	w = (long unsigned) charP;
	w = w / d;
	w = w * d;
	return((long*)w);
}

static unsigned
BitIndex(unsigned char * charP)
{
	long unsigned w;
	long unsigned bitsPerWord;
	bitsPerWord = sizeof(long) * 8;
	w = (long unsigned) charP;
	return ((w * 8) % bitsPerWord);
}

static CII←RES
setblackhalftone(CII←Handle h, int lines, int dots, unsigned phase, unsigned char thresh[])
{
	CII←RES res = CII←RES←ok;
	CII←HalftonePropertiesForSeparation hps[1];
	CII←HalftoneProperties hp = (void*)0;
	
	hps[0].halftoneType = (char*)0;
	hps[0].toner = CII←TONER←BLACK;
	hps[0].maxSample = 255;
	hps[0].thresholds.sMinBox = 0;
	hps[0].thresholds.fMinBox = 0;
	hps[0].thresholds.sMaxBox = lines;
	hps[0].thresholds.fMaxBox = dots;
	hps[0].thresholds.bitsPerSample = 8;
	hps[0].thresholds.bitsPerLine = 8*dots;
	hps[0].thresholds.basePointer = WordPointer(thresh);
	hps[0].thresholds.bitIndex = BitIndex(thresh);
	hps[0].thresholds.ref = (void*)0;
	hps[0].phase = phase;
	hps[0].reserved = (void*)0;
	
	CHK(CII←MakeHalftoneProperties(h, 1, hps, &hp));
	CHK(CII←SetHalftoneProperties(h, hp));
	CHK(CII←DestroyHalftoneProperties(h, hp));

	return(res);
}

extern CII←RES
run←ciitesthalftone(CII←Handle h)
{
	CII←RES res = CII←RES←ok;
	float matrix[6];
	float savematrix[6];
	CII←HalftoneProperties hpsave = (void*)0;
	
	CHK(CII←GetMatrix(h, savematrix));
	CHK(CII←GetMatrix(h, matrix));
	CHK(CIU←ApplyPreTranslate(72.0, 144.0, matrix));
	CHK(CIU←ApplyPreScale(2.0, matrix));
	CHK(CII←SetMatrix(h, matrix));
	
	CHK(graywedge(h));
	
	CHK(CIU←ApplyPreTranslate(105.0, 0.0, matrix));
	CHK(CII←SetMatrix(h, matrix));
	{
	   unsigned char thresh[8] =
	   {
	      159,  64,  32, 223,
	        0, 254, 191, 127
	   };
	   CHK(setblackhalftone(h, 4, 2, 4, thresh));
	}
	CHK(CII←GetHalftoneProperties(h, &hpsave));
	CHK(graywedge(h));
	
	CHK(CII←GetHalftoneProperties(h, &hpsave));

	{
	   unsigned char thresh[8] =
	   {
	       0, 30, 200, 115,  60, 225, 160, 90
	   };
	   CHK(setblackhalftone(h, 1, 7, 3, thresh+1));
	}
	{
	   unsigned char thresh[7] =
	   {
	       30, 200, 115,  60, 225, 160, 90
	   };
	   CHK(setblackhalftone(h, 1, 7, 3, thresh));
	}

	CHK(CIU←ApplyPreTranslate(-105.0, 105.0, matrix));
	CHK(CII←SetMatrix(h, matrix));
	CHK(graywedge(h));
	
	CHK(CIU←ApplyPreTranslate(105.0, 0.0, matrix));
	CHK(CII←SetMatrix(h, matrix));
	CHK(CII←SetHalftoneProperties(h, hpsave));
	CHK(graywedge(h));
	
	CHK(CII←DestroyHalftoneProperties(h, hpsave));
	
	CHK(CII←SetMatrix(h, savematrix));
	return(res);
}

extern void
XR←run←ciitesthalftone()
{
	CII←Handle h = (CII←Handle)CII←TestDevice();
	float t[6];
	CII←GetInitialMatrix(h, t);
	CII←SetMatrix(h, t);
	run←ciitesthalftone(h);
	CII←Destroy(h);
}