#include "XPlatform.h"
#include <stdio.h>
#include <Util/BaseMultiStreamIO.h>


struct PGMReadInfo
{
	FILE* fp;
	char* data;
	int width;
	int ascii , pgm;
};

void* PGMInitReadColor( char* fileName , int& width , int& height , MultiStreamIOServer* ioServer )
{
	PGMReadInfo* info = (PGMReadInfo*)malloc( sizeof( PGMReadInfo ) );
	info->fp = fopen( fileName , "rb" );
	if( !info->fp ) fprintf( stderr , "Failed to open: %s\n" , fileName ) , exit(0);

#if 1
	char header[512];
	int maxValue;
	if( fscanf( info->fp , "%s %d %d %d" , header , &width , &height , &maxValue )!=4 ) 
		fprintf( stderr , "Failed to parse header\n" ) , exit( 0 );
	while (fgetc( info->fp ) != '\n');
	if( ( strcasecmp( header , "P5" ) ) && ( strcasecmp( header , "P2" ) ) &&  // binary and ascii pgm
		( strcasecmp( header , "P6" ) ) && ( strcasecmp( header , "P3" ) ) )   // binary and ascii ppm
		fprintf( stderr , "Error: binary/ascii PPM (P6/P3) or binary/ascii PGM only (P5/P2): %s\n" , header ) , exit( 0 );
	info->ascii = ( !strcasecmp( header , "P2" ) ) || ( !strcasecmp( header , "P3" ) );
	info->pgm   = ( !strcasecmp( header , "P5" ) ) || ( !strcasecmp( header , "P2" ) );
#else
	char line[500];
	fgets( line , 500 , info->fp );
	int i = strlen( line );
	if( i>500 ) i=500;
	while( line[i-1]=='\n' || line[i-1]=='\r' )
	{
		line[i-1]=0;
		i--;
	}
	if( ( stricmp( line , "P5" ) ) && ( stricmp( line , "P2" ) ) &&  // binary and ascii pgm
		( stricmp( line , "P6" ) ) && ( stricmp( line , "P3" ) ) )   // binary and ascii ppm
		fprintf( stderr , "Error: binary/ascii PPM (P6/P3) or binary/ascii PGM only (P5/P2): %s\n" , line ) , exit( 0 );
	info->ascii = ( !stricmp( line , "P2" ) ) || ( !stricmp( line , "P3" ) );
	info->pgm   = ( !stricmp( line , "P5" ) ) || ( !stricmp( line , "P2" ) );
	do
	{
		fgets( line , 500 , info->fp );
		if( strlen( line ) )
			if ( line[0]!='#' ) sscanf( line , " %d %d " , &width , &height );
	}
	while( ( line[0]=='#' ) || !strlen(line) );
#endif

	info->width = width;
	info->data = new char[ width*3 ];
	if( !info->data ) fprintf( stderr , "Could not allocate memory for bitmap data\n" ) , exit( 0 );

	return info;
}
void PGMGetImageSize( char* fileName , int& width , int& height )
{
	FILE* fp = fopen( fileName , "rb" );
	if( !fp ) fprintf( stderr , "Failed to open: %s\n" , fileName ) , exit(0);

#if 1
	char header[512];
	int maxValue;
	if( fscanf( fp , "%s %d %d %d" , header , &width , &height , &maxValue )!=4 ) 
		fprintf( stderr , "Failed to parse header\n" ) , exit( 0 );
	while (fgetc( fp ) != '\n');
	if( ( strcasecmp( header , "P5" ) ) && ( strcasecmp( header , "P2" ) ) &&  // binary and ascii pgm
		( strcasecmp( header , "P6" ) ) && ( strcasecmp( header , "P3" ) ) )   // binary and ascii ppm
		fprintf( stderr , "Error: binary/ascii PPM (P6/P3) or binary/ascii PGM only (P5/P2): %s\n" , header ) , exit( 0 );
	int ascii = ( !strcasecmp( header , "P2" ) ) || ( !strcasecmp( header , "P3" ) );
	int pgm   = ( !strcasecmp( header , "P5" ) ) || ( !strcasecmp( header , "P2" ) );
#else
	char line[500];
	fgets( line , 500 , fp );
	int i = strlen( line );
	if( i>500 ) i=500;
	while( line[i-1]=='\n' || line[i-1]=='\r' )
	{
		line[i-1]=0;
		i--;
	}
	if( ( stricmp( line , "P5" ) ) && ( stricmp( line , "P2" ) ) &&  // binary and ascii pgm
		( stricmp( line , "P6" ) ) && ( stricmp( line , "P3" ) ) )   // binary and ascii ppm
		fprintf( stderr , "Error: binary/ascii PPM (P6/P3) or binary/ascii PGM only (P5/P2): %s\n" , line ) , exit( 0 );
	do
	{
		fgets( line , 500 , fp );
		if( strlen( line ) )
			if ( line[0]!='#' ) sscanf( line , " %d %d " , &width , &height );
	}
	while( ( line[0]=='#' ) || !strlen(line) );
#endif
	
	fclose( fp );
}

void PGMReadColorRow( void* pixels , void* v , int j )
{
	PGMReadInfo* info = ( PGMReadInfo* )v;
	unsigned char pixel_byte;
	if( info->pgm )
		if( info->ascii )
			for( int i=0 ; i<info->width ; i++ )
			{
				int pixel_int;
				fscanf( info->fp , " %d " , &pixel_int );
				pixel_byte = (unsigned char) pixel_int;
				info->data[3*i] = info->data[3*i+1] = info->data[3*i+2] = pixel_byte;
			}
		else
			for( int i=0 ; i<info->width ; i++ )
			{
				fscanf( info->fp , "%c" , &pixel_byte );
				info->data[3*i] = info->data[3*i+1] = info->data[3*i+2] = pixel_byte;
			}
	else
		if( info->ascii )
#if 1
		{
			int pixel_int[3];
			for( int i=0 ; i<info->width ; i++ )
			{
				fscanf( info->fp , " %d %d %d " , pixel_int+0 , pixel_int+1 , pixel_int+2 );
				info->data[3*i+0] = (unsigned char) pixel_int[0];
				info->data[3*i+1] = (unsigned char) pixel_int[1];
				info->data[3*i+2] = (unsigned char) pixel_int[2];
			}
		}
#else
			for( int i=0 ; i<info->width ; i++ ) fscanf( info->fp , "%c%c%c" , info->data+3*i , info->data+3*i+1 , info->data+3*i+2 );
#endif
		else
			fread( info->data , sizeof(unsigned char) , 3*info->width , info->fp );
	unsigned char *p = (unsigned char*) pixels;
	memcpy( pixels , info->data , sizeof( unsigned char ) * 3 * info->width );
}

void PGMFinalizeRead( void* v  )
{
	PGMReadInfo* info = ( PGMReadInfo* )v;
	fclose( info->fp );
	delete[] info->data;
	free( info );
}