/*  Simple PPM functions.  See sample main function for usage.
 *      
 *  int  get_ppm_from_file( image * x, FILE * fp ) -- allocates and 
 *                            reads a binary PPM ("P6") from a file.
 *  int  copy_ppm( image x, image * y ) -- allocates a copy of x, puts in *y.
 *
 *  Allocation functions return a nonzero value if successful.
 *
 *  void put_ppm_to_file( image x, FILE * gp ) -- writes x to a file.
 *  void dealloc_ppm( image x ) -- frees an allocated image.
 *
 *  pixel get_pixel( image z, int x, int y ) --- get RGB pixel at (x,y)
 *  void  put_pixel( image z, int x, int y, pixel p ) -- places pixel at (x,y)
 */

typedef unsigned char BYTE;
typedef struct pixel_struct { int rgb[3]; } pixel;
typedef struct image_struct {
	int width, height, max, bpp, raster;
	BYTE * raw;
	BYTE ** pixel;    
} image;

pixel get_pixel( image z, int x, int y )
{
	BYTE * foo, i;
	pixel p;
	for( i=0; i<3; i++) {
		p.rgb[i] = z.pixel[y][(i+x*3)*z.bpp];
		if( z.bpp!=1 ) p.rgb[i] = (p.rgb[i]<<8) + z.pixel[y][(i+x*3)*z.bpp+1];
	}
	return p;
}

void put_pixel( image z, int x, int y, pixel p )
{
	BYTE * foo, i;
	for( i=0; i<3; i++) {
		z.pixel[y][(i+3*x)*z.bpp] = p.rgb[i] & 0xff;
		if( z.bpp!=1 ) { 
			z.pixel[y][(i+3*x)*z.bpp+1] = z.pixel[y][(i+3*x)*z.bpp];
		        z.pixel[y][(i+3*x)*z.bpp] = (p.rgb[i]>>8) & 0xff;
		}
	}
}

int alloc_ppm( image * y ) {
	int i=0;
	y->raw    = (BYTE *) malloc( y->height * y->raster );
	y->pixel  = (BYTE **) malloc( y->height * sizeof(BYTE*) );
	if( y->raw!=NULL && y->pixel!=NULL ) 
		for( i=0; i<y->height; i++ ) 
			y->pixel[i] = y->raw + i*y->raster;
	else fprintf( stderr, "Failed to allocate memory!\n" );
	return i;
}

void dealloc_ppm( image x ) {
	free( x.pixel );
	free( x.raw );
}

int copy_ppm( image x, image * y ) {
	int i=0;
	*y = x;
	if( alloc_ppm(y) ) 
		for( i=0; i<y->height*y->raster; i++ ) 
			y->raw[i] = x.raw[i];
	return i;
}

int get_int( FILE * fp ) { /* scan int from ppm, passing over comments */
	int k;
	unsigned char ch;
	do {
		while( isspace(ch=getc(fp)) ) ;
		if( ch=='#' ) while( (ch=getc(fp))!='\n' ) ;
	} while( !isdigit(ch) );
	for( k=(ch-'0'); isdigit(ch=getc(fp)); k = 10*k+(ch-'0') );
	return k;
}

int get_ppm_from_file( image * x, FILE * fp ) {
	int flag=0;
	char magic[3]="ZZ";

	fread(magic,2,1,fp);	
	if( strcmp(magic,"P6")==0 ) {
		x->width=get_int(fp); x->height=get_int(fp); x->max=get_int(fp);
		x->bpp = (x->max<256) ? 1 : 2;
		x->raster = x->width * x->bpp * 3;
		if( flag=alloc_ppm(x) ) 
			fread( x->raw, x->height, x->raster, fp );
	}
	else fprintf( stderr, "This is not a valid binary PPM (magic # is not P6)\n" );
	return flag;
}

void put_ppm_to_file( image x, FILE * gp )
{
	fprintf( gp, "P6\n%d %d %d\n", x.width, x.height, x.max ) ;
	fwrite( x.raw, x.height, x.raster, gp );
}
