/* Generated by tgr */

#import "PageView.h"
#import "SheetView.h"
#import <dpsclient/wraps.h>
#import "TVWindow.h"
#import "TeXviewObject.h"
#import "dviAccessors.h"
#import <appkit/NXCursor.h>
#import <appkit/Application.h>
#import <appkit/NXBitmapImageRep.h>
#import <libc.h>

@implementation SheetView

SheetView *myView ;
PageView *myPageView ;

extern shalfword hh, vv ;
extern shalfword hhoffset, vvoffset ;
extern shalfword hhmin, hhmax, vvmin, vvmax ;
extern shalfword hhsize, vvsize ;
extern shalfword rhhsize, rvvsize ;
extern shalfword hhmarg, vvmarg ;
extern Boolean orientationset ;
extern Boolean landscape ;
extern Boolean dualpage ;
extern FILE *dvifile ;
extern integer pagenum, seq ;
extern fontdesctype *curfnt ;
extern char realname[] ;
extern int curpsfont ;
extern TeXviewObject *myTeXviewObject ;
Boolean pagedrawn ;

extern id fpageinit() ;
extern void makeraster(), outline() ;
extern void dopage(), error() ;
extern void free(), pagereport() ;
extern void tolandscape() ;
extern void reportname() ;
extern void TPSinit(), TPSselfont(), TPSshow(), TPSQshow(), TPSmoveto() ;
extern void TPShmove(), TPSxshow() ;
extern void fixalertbug() ;
static int offset = 0 ;

+ newFrame:(const NXRect *)theFrame
{
   NXSize nxs ;
   self = [super newFrame:theFrame];
   nxs.width = mhhsize = 1036 ;
   nxs.height = mvvsize = 1336 ;
   cache = [NXImage newSize:&nxs] ;
   [cache setFlipped:YES] ;
   nxs.width = 1036 / 2;
   nxs.height = 1336 / 2;
   otherCache = [NXImage newSize:&nxs];
   return self ;
}

id makenewdoc(hsize, vsize)
int hsize, vsize ;
{
   return [myView makeNewDoc:hsize:vsize] ;
}

- makeNewDoc:(int)hsize:(int)vsize
{
//   if (hsize == ohhsize && vsize == ovvsize)
//      return 0;
   ohhsize = hsize ;
   ovvsize = vsize ;
   [myPageView noScrollUpdates] ;
   [myPageView cachePosition:hsize:vsize] ;
   if (hsize > mhhsize || vsize > mvvsize) {
      NXSize nxs ;
      if (hsize > mhhsize)
         mhhsize = hsize ;
      if (vsize > mvvsize)
         mvvsize = vsize ;
      nxs.width = mhhsize ;
      nxs.height = mvvsize ;
      [cache setSize:&nxs] ;
      //the smaller gray cache
      nxs.width = mhhsize / 2;
      nxs.height = mvvsize / 2;
      [otherCache setSize:&nxs];
   }
   offset = mvvsize - vsize ;
   if ([myTeXviewObject doGray])
      [self sizeTo:hsize / 2:vsize / 2];
   else
      [self sizeTo:hsize:vsize] ;
   [myPageView unCachePosition:hsize:vsize] ;
   [myPageView scrollUpdates] ;
   return self ;
}

- update
{
   if ([self needsDisplay])
      [self display] ;
   return(self) ;
}

static int dontbother = 1 ;

void display()
{
   dontbother = 1 ;
   (void)fpageinit() ;
   dontbother = 0 ;
   [myView display] ;
}


//
//	doGray:origData	-	this routine does the gray scale conversion
//
//	origData	-	a NXBitmapImageRep with the bi-level bitmap to be grayscaled
//				(from the machportdevice)

inline unsigned char convert24( unsigned char byte1, unsigned char byte2 )
{
	unsigned char dest;
	
	dest=( byte1 & 1 ) | ( (byte1 & 4) >> 1) | ((byte1 & 16)>>2) | ((byte1 & 64)>>3);
	dest<<=4;
	dest|=( byte2 & 1 ) | ( (byte2 & 4) >> 1) | ((byte2 & 16)>>2) | ((byte2 & 64)>>3);

	return dest;
}


-doGray:origData
{
//	unsigned char *source;
	unsigned char *destBuf;
	unsigned short *sourceWords;
	unsigned char sourceByte1,sourceByte2;
	int  bytesPerRow,wordsPerRow ,bytesPerRowDest,i,j;
	id grayCache;
	int h,w;
	static unsigned char  nib_count[17]={ 0,0,0,1,0,1,1,2,0,1,1,2,1,2,2,3  };
//	static unsigned char  nib_count[17]={ 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,3  };
//	static unsigned char  nib_count[17]={ 0,2,2,3,2,3,3,3,2,3,3,3,3,3,3,3  };
	static unsigned char  byte2nib[256];
	static unsigned char  look_nibs[65538];
	static unsigned char  two2one[65538];
	static int inited=0;
	struct timeval start,end;
	struct timezone tz;
			
	//	a little timing
	
	for (i=0; i<256; i++ )
		byte2nib[i]=convert24( 0, i );
	
	if (!inited)
	{
		for(i=0;i<65536;i++)
		{
			unsigned char dest_byte=0;
			unsigned char sourceByte1=(i>>8) & 255;
			unsigned char sourceByte2=(i & 255);
			
			dest_byte |= nib_count[ (( sourceByte1 >> 6 ) & 3) | (( sourceByte2 >> 4) & (3<<2))] << 6;
			dest_byte |= nib_count[ (( sourceByte1 >> 4) & 3) | (( sourceByte2 >> 2) & (3<<2))] << 4;
			dest_byte |= nib_count[ (( sourceByte1 >> 2) & 3) | ( sourceByte2  & (3 << 2))] << 2;
			dest_byte |= nib_count[ (( sourceByte1 ) & 3) | (( sourceByte2 << 2) & (3 << 2))];
			
			look_nibs[i]=dest_byte;
			
#if	__BIG_ENDIAN__
			two2one[i]=(byte2nib[ sourceByte1 ] << 4) | byte2nib[sourceByte2];
#elif	__LITTLE_ENDIAN__
			two2one[i]=(byte2nib[ sourceByte1 ] ) | (byte2nib[sourceByte2] << 4);
#endif		
		}
		inited=1;
	}
	
	gettimeofday( &start, &tz );

	//	allocate the gray bitmap, half the size (x and y) of the original
	//	but with 2 bits per pixel
	
	grayCache=[[NXBitmapImageRep allocFromZone:[self zone]] 
					initData:NULL 
					pixelsWide:w=[origData pixelsWide] / 2
					pixelsHigh:h=[origData pixelsHigh] / 2
					bitsPerSample:2
					samplesPerPixel:[origData samplesPerPixel]
					hasAlpha:NO isPlanar:NO
					colorSpace: [origData colorSpace]
					bytesPerRow:0 bitsPerPixel:0];

	//	info needed for accessing the data directly

	bytesPerRow = [origData bytesPerRow] ;
	bytesPerRowDest= [grayCache bytesPerRow];
	wordsPerRow	= bytesPerRow/2;
//	printf("bytesPerRow=%d\n",bytesPerRow);
	//	do the conversion of the bit data

	for ( i=0, destBuf=[grayCache data],sourceWords=[origData data];
		i<h*2   ;
		 i+=2, destBuf += bytesPerRowDest, sourceWords+=wordsPerRow*2 )
	{
		for (j=0; j< bytesPerRowDest ; j++ )
		{
			unsigned char dest_byte;
			sourceByte1 =  two2one[sourceWords[j]];
			sourceByte2 = two2one[sourceWords[j+wordsPerRow]];
			dest_byte=0;

			destBuf[ j] = look_nibs[(sourceByte1 << 8) | sourceByte2];
		}
//		memcpy( destBuf, destTemp, bytesPerRowDest );
	}
	
	
	//	timing again
	
	gettimeofday( &end, &tz );
	end.tv_sec -= start.tv_sec;
	end.tv_usec -= start.tv_usec;
	if ( end.tv_usec < 0 )
	{
		end.tv_sec--;
		end.tv_usec+= 1000000;
	}
// 	printf("time spent in doGray = %d second, %d micros\n", end.tv_sec,end.tv_usec );

	return grayCache;
	
	return self;
}



-setDrawn
{
	pagedrawn=YES;
	return self;
}

- drawSelf:(NXRect *)rects :(int)rectCount
{
    NXRect r ;
	int             i;
    if (dontbother)
       return self ;
    if ((! pagedrawn)) {
        [window useOptimizedDrawing:YES];
        [cache lockFocus] ;
		if (offset)
		{
//			printf("offset: %d\n",offset);
			PStranslate(0, offset);
		}
/*     PSsetgray(1.0) ; */
       NX_WIDTH(&r) = rhhsize ;
       NX_HEIGHT(&r) = rvvsize ;
       NX_X(&r) = 0 ;
       NX_Y(&r) = 0 ;
       NXEraseRect(&r) ;
/*     PSclippath() ;
       PSfill() ; */
       PSsetgray(0.0) ;
       outline() ;
       if (dvifile != NULL)
          dopage() ;
//		if ([myTeXviewObject doGray])
		{
			id              image, gray;
			PSgsave();
//			PStranslate(0, -offset);
			image = [[NXBitmapImageRep alloc] initData:NULL fromRect:&r];
			gray = [self doGray:image];
			[otherCache lockFocus];
			[gray draw];
			[otherCache unlockFocus];
			[image free];
			[gray free];
			PSgrestore();
		}
       [cache unlockFocus] ;
#ifdef TRACKCACHE
       { int bsize, bmax, msize;
         PScachestatus(&bsize, &bmax, &msize) ;
         printf("bsize=%d bmax=%d msize=%d\n", bsize, bmax, msize) ;
       }
       { int used, max, level;
         PSvmstatus(&level, &used, &max) ;
         printf("vmused=%d\n", used) ;
       }
#endif
    }
	//PSflush();
	//[window setBackingType:NX_RETAINED];
	for (i = rectCount > 1 ? 1 : 0; i < rectCount; i++)
	{
		if ([myTeXviewObject doGray])
			[otherCache composite:NX_COPY fromRect:&rects[i] toPoint:&rects[i].origin];
		else
			[cache composite:NX_COPY fromRect:&rects[i] toPoint:&rects[i].origin];
	}
	//[window setBackingType:NX_BUFFERED];
    return self;
}

- free
{
   if (cache) [cache free];
   return [super free];
}

#define SHOWBUFSIZE (2000)
static char showbuf[SHOWBUFSIZE] ;
static char *showbufp = showbuf ;
static int showx[SHOWBUFSIZE] ;
static int *showxp = showx ;
static int rhh = -3200, rvv = -3200 ;

void strflush() {
   if (showx[0] && showbufp > showbuf)
      TPShmove(showx[0]) ;
   if (showbufp > showbuf) {
      if (rhh > -3000) {
         *showxp++ = hh - rhh ;
         rhh = hh ;
      } else
         *showxp++ = 0 ;
      TPSxshow(showbuf, &(showx[1]), showbufp - showbuf) ;
/*    TPSshow(showbuf, showbufp - showbuf) ; */
      showbufp = showbuf ;
      showxp = showx ;
   }
}

void texflush() {
   strflush() ;
   rhh = -3200 ;
   rvv = -3200 ;
   curpsfont = -1 ;
}

void fdrawrule(xx, yy)
halfword xx, yy ;
{
   register shalfword hmin, hmax, vmin, vmax ;

   if (xx>0 && yy>0) {
      hmin = hh+hhoffset ;
      hmax = hmin + xx - 1 ;
      vmax = vv+vvoffset ;
      vmin = vmax - yy + 1 ;
      [myView drawRule:xx:yy] ;
   }
}

- drawRule:(int)x:(int)y
{
   PSrectfill(hh + hhoffset, vv + vvoffset - y, x, y) ;
   return(self) ;
}
@end

void hvpos() {
   texflush() ;
   TPSmoveto(hh + hhoffset, vv + vvoffset) ;
   rhh = hh ;
   rvv = vv ;
}

void fdrawchar(c, e)
char c ;
int e ;
{
   if (rvv == vv) {
/*    if (rhh != hh) {
         if (showbufp > showbuf) {
            TPSQshow(showbuf, showbufp-showbuf, hh-rhh) ;
            showbufp = showbuf ;
         } else
            TPSmoveto(hh + hhoffset, vv + vvoffset) ;
         rhh = hh ;
      } */
      if (rhh < -3000)
         hvpos() ;
   } else {
      strflush() ;
      TPSmoveto(hh + hhoffset, vv + vvoffset) ;
      rhh = hh ;
      rvv = vv ;
   }
   *showbufp++ = c ;
   *showxp++ = hh - rhh ;
   rhh = hh ;
}
/*
 *   Set things up for a new page, including calculating the number of
 *   raster rows we have in the buffer.  Everything must be 16-bit
 *   aligned.
 */
id fpageinit() {
   if (landscape && !orientationset)
      tolandscape() ;
   return makenewdoc(rhhsize, rvvsize) ;
}

void outline() {
   int safehh, safevv ;

   pagereport(pagenum, seq) ;
   safehh = hh ; safevv = vv ;
   hh = - hhmarg - 2 ; vv = - vvmarg - 1 ;
   fdrawrule(hhsize + 4, 2) ;
   vv = vvsize - vvmarg ;
   fdrawrule(2, vvsize + 2) ;
   fdrawrule(hhsize + 4, 2) ;
   hh = hhsize - hhmarg ;
   fdrawrule(2, vvsize + 2) ;
   if (dualpage) {
      hh = hhsize / 2 - hhmarg - 1 ;
      fdrawrule(2, vvsize + 2) ;
   }
   hh = safehh ;
   vv = safevv ;
   orientationset = 1 ;
}
