#include <stdio.h>
#include <string.h>

#include <exec/execbase.h>
#include <exec/memory.h>
#include <exec/types.h>
#include <intuition/intuition.h>
#include <intuition/intuitionbase.h>
#include <cybergraphics/cybergraphics.h>

#include <proof/proof.h>
#include <proof/proof_protos.h>
#include <proof/proof_pragmas.h>

#include <clib/exec_protos.h>
#include <clib/dos_protos.h>
#include <clib/intuition_protos.h>
#include <clib/cybergraphics_protos.h>

#include <pragmas/exec_pragmas.h>
#include <pragmas/dos_pragmas.h>
#include <pragmas/intuition_pragmas.h>
#include <pragmas/cybergraphics_pragmas.h>

#include <jpeg/jpeg.h>
#include <jpeg/jpeg_protos.h>
#include <jpeg/jpeg_pragmas.h>

#include "scale.h"

/* Function prototypes */
extern void scale_region( struct PixelRegion *srcPR, struct PixelRegion *destPR, BOOL cubic_interpolation );

/* Global variables */
extern struct Library *DOSBase;
struct Library *ProofBase, *JpegBase;

char *version = "$VER: ProofCreate 1.0 (19.1.99)";

void main( int argc, char **argv )
{
	LONG width = 80, height = 65, jpegquality = 85;
	void *mempool = NULL;

	mempool = CreatePool( MEMF_PUBLIC | MEMF_CLEAR, 8000, 4000 );
	ProofBase = OpenLibrary( "proof.library", NULL );
	JpegBase = OpenLibrary( "jpeg.library", NULL );
	if ( ProofBase != NULL && JpegBase != NULL && mempool != NULL )
	{
		if ( argc > 1 )
		{
			struct Proof *pf = NULL;

			UBYTE *rgbBuffer = NULL, *scaledBuffer = NULL;
			UBYTE depth, dflags = NULL;
			DOUBLE xzoom, yzoom;
			LONG fileSize;
			ULONG err = 0, scaledWidth, scaledHeight, finalWidth, finalHeight;
			ULONG x, y, denom;
			struct JPEGDecHandle *jph;
			UBYTE *jstream;
			ULONG jstreamsize;
			struct FileInfoBlock *fib;
			BPTR lock, fp;
			UBYTE colourspace;
			ULONG bpp;

			/* Get the size of the original image file */
			fib = AllocDosObject ( DOS_FIB, NULL );

			/* Place a lock on the file */
			lock = Lock( argv[1], ACCESS_READ );

			if ( lock )
			{
				if ( Examine( lock, fib ) != NULL )
				{
					fileSize = fib->fib_Size;
				}
				jstreamsize = fileSize;
				jstream = AllocVec( jstreamsize, MEMF_PUBLIC | MEMF_CLEAR );
				if ( jstream != NULL )
				{
					fp = OpenFromLock( lock );
					if ( fp != NULL )
					{
						/* Spool file into memory */
						Read( fp, jstream, jstreamsize );

						Close( fp );

						err = AllocJPEGDecompress( &jph, JPG_SrcMemStream, jstream,
							JPG_SrcMemStreamSize, jstreamsize, TAG_DONE );
						if ( !err )
						{
							err = GetJPEGInfo( (struct JPEGHandle *)jph, JPG_Width, &x, JPG_Height, &y,
								JPG_ColourSpace, &colourspace,
								JPG_BytesPerPixel, &bpp,
								JPG_ScaleNum, 1, JPG_ScaleDenom, 1, TAG_DONE );
							if ( !err )
							{
								if ( colourspace == JPCS_GRAYSCALE )
								{
									dflags = PDFF_24BIT | PDFF_GREY;

									depth = 8;
								}
								else
								{
									dflags = PDFF_24BIT | PDFF_CHUNKY;

									depth = 24;
								}

								err = AllocProof( &pf,
									PFN_ImageWidth, x,
									PFN_ImageHeight, y,
									PFN_ImageDepth, depth,
									PFN_ImageType, PDIV_JPEG,
									PFN_ImageFormat, dflags,
									PFN_ImageFileSize, fileSize,
									PFN_CategoryOwner, 87,
									PFN_ImageGroup, 1,
									PFN_ImageCategory, 47,
									PFN_ProofQuestionable, TRUE,
									PFN_ProofAspectX, 22,
									PFN_ProofAspectY, 22,
									PFN_MemoryPool, mempool,
									TAG_DONE );
								if ( ! err )
								{
									/* This is divided by 2 on each pass of the loop.*/
									denom = 16;

									/* Now check what scale factor is required by the jpeg loader.*/
									do
									{
										denom /= 2;

										err = GetJPEGInfo( (struct JPEGHandle *)jph, JPG_Width, &scaledWidth, JPG_Height, &scaledHeight,
											JPG_ScaleNum, 1, JPG_ScaleDenom, denom, TAG_DONE );

									} while( scaledWidth < width || scaledHeight < height );

									rgbBuffer = AllocVec( scaledWidth * scaledHeight * 3, MEMF_PUBLIC | MEMF_CLEAR );
									if ( rgbBuffer )
									{
										err = DecompressJPEG( jph, JPG_DestRGBBuffer, rgbBuffer,
											JPG_ScaleNum, 1, JPG_ScaleDenom, denom,
											TAG_DONE );
										if ( !err )
										{
											/* Now calculate the required zoom factor to scale the image to the exact size.*/
											xzoom = ( double ) width / ( double ) scaledWidth;

											yzoom = ( double ) height / ( double ) scaledHeight;

											if ( xzoom < yzoom )
											{
												finalWidth = xzoom * scaledWidth;
												finalHeight = xzoom * scaledHeight;

												yzoom = ( double ) finalHeight / ( double ) scaledHeight;
											}
											else
											{
												finalHeight = yzoom * scaledHeight;
												finalWidth = yzoom * scaledWidth;

												xzoom = ( double ) finalWidth / ( double ) scaledWidth;
											}

											scaledBuffer = AllocVec( finalWidth * finalHeight * bpp, MEMF_PUBLIC | MEMF_CLEAR );
											if ( scaledBuffer != NULL )
											{
												struct PixelRegion src, dest;

												src.buf = rgbBuffer;
												src.w = scaledWidth;
												src.h = scaledHeight;
												src.bytes = bpp;

												dest.buf = scaledBuffer;
												dest.w = finalWidth;
												dest.h = finalHeight;
												dest.bytes = bpp;

												scale_region( &src, &dest, TRUE );

												err = SaveProof( &pf,
													PFN_ImagePathName, argv[1],
													PFN_ProofPath, "RAM:",
													PFN_ProofWidth, finalWidth,
													PFN_ProofHeight, finalHeight,
													PFN_ProofBodyType, PHBV_JFIF,
													PFN_RGBTripletBuffer, scaledBuffer,
													PFN_JFIFQuality, jpegquality,
													PFN_MemoryPool, mempool,
													TAG_DONE );
												if ( err == PFERR_NONE )
												{
													printf("proof saved\n");
												}
												else printf("proof error 2=%d\n",err);

												FreeVec( scaledBuffer );
											}
											else printf("cant allocate scaled buffer\n");
										}
										else printf("jpeg error 3=%d\n",err);

										FreeVec( rgbBuffer );
									}
									else printf("cant allocate load jpeg buffer");

									FreeProof( &pf, PFN_MemoryPool, mempool, TAG_DONE );
								}
								else printf("proof error 1=%d\n",err);
							}
							else printf("jpeg error 2=%d\n",err);

							FreeJPEGDecompress( jph );
						}
						else printf("jpeg error 1=%d\n",err);
					}
					else UnLock( lock );

					FreeVec( jstream );
				}
				else printf("cant allocate source file memory");
			}
			else printf("cant lock file");


			if ( fib ) FreeDosObject( DOS_FIB, fib );
		}
	}

	if ( ProofBase != NULL ) CloseLibrary( ProofBase );
	if ( JpegBase != NULL ) CloseLibrary( JpegBase );

	if ( mempool != NULL ) DeletePool( mempool );
	else printf("cant allocate memory pool\n");
}
