
#include "EgCommon.h"
#include "CEgFileSpec.h"
#include "CEgIOFile.h"

long CEgIOFile::sCreatorType = MCC4_TO_INT("\?\?\?\?");

CEgIOFile::CEgIOFile( int inDoTrunc, long inOBufSize )
	: CEgOStream(), CEgIFile(), mDoTrunc( inDoTrunc )
{

	mDoTrunc = inDoTrunc;
	mOBufSize = inOBufSize;
	
	if ( mOBufSize < 100 )
		mOBufSize = 100;
}

CEgIOFile::~CEgIOFile() {

	close();
}

#include <stdio.h>

#define __OSWOpen( specPtr ) \
	mFile = (long) fopen( (char*) (specPtr -> OSSpec()), "w+b" );		

#define __OSWrite( srcePtr, ioBytes ) \
	unsigned long int wrote = fwrite( srcePtr, 1, ioBytes, (FILE*) mFile );		\
	if ( wrote > 0 || ioBytes == 0 )						\
		ioBytes = wrote;							\
	else {										\
		throwErr( cWriteErr );							\
	}

void CEgIOFile::open( const CEgFileSpec* inSpecPtr ) {
	
	close();
	throwErr( cNoErr );

	if ( inSpecPtr ) {
		if ( mDoTrunc )
			inSpecPtr -> Delete();

		__OSWOpen( inSpecPtr )
	}

	if ( mFile == 0 ) {
		#if EG_MAC
		if ( mOSErr == fnfErr )
		#elif defined(UNIX_X)
		  if (0)   /* FIXME */
		#else
		if ( mOSErr == ERROR_FILE_NOT_FOUND )
		#endif
			throwErr( cFileNotFound );
		else
			throwErr( cOpenErr );
	}
}

void CEgIOFile::PutBlock( const void* inSrce, long numBytes ) {

	CEgIFile::skip( numBytes );										// Keep mPos up to date
	
	// If we don't want to exceed our buffer limit...
	if ( numBytes + (long) mOBuf.length() > mOBufSize ) {	// Uh oh, we actually  have to write to disk
		// Get rid of what we have waiting first
		flush();
		
		if ( numBytes > mOBufSize /4  && noErr() ) {
			__OSWrite( inSrce, numBytes ) }
		else
			CEgOStream::PutBlock( inSrce, numBytes ); }
	else
		CEgOStream::PutBlock( inSrce, numBytes );
}

/*
void CEgIOFile::PutBlock( const void* inSrce, long numBytes ) {
	
	CEgIFile::skip( numBytes );					// Keep mPos up to date
	if ( numBytes + (long) mOBuf.length() >= cMaxOBufSize )		// Uh oh, we actually  have to write to disk
		flush();						// Dump our buf to disk

	while ( numBytes > cMaxOBufSize ) {				// We do this loop crap because to avoid code duplication/maintainance and
		PutBlock( inSrce, cMaxOBufSize );			// to avoid giving OSWrite a NULL srce ptr (which is perfectly valid from a skip call)
		if ( inSrce )
			inSrce = (char*) inSrce + cMaxOBufSize;
		numBytes -= cMaxOBufSize;
	}

	CEgOStream::PutBlock( inSrce, numBytes );
}
*/

void CEgIOFile::flush() {

	long ioBytes = mOBuf.length();
	
	if ( ! mFile )
		throwErr( cNotOpen );
	else if ( ioBytes > 0 && noErr() ) {
		__OSWrite( mOBuf.getCStr(), ioBytes )	
		if ( noErr() ) {
			invalidateBuf();			// Invalidate read buffer
			mOBuf.Wipe();				// We're done with the out buffer
		}
	}
}

long CEgIOFile::size() {

	flush();
	
	return CEgIFile::size();
}

void CEgIOFile::seek( long inPos ) {
	
	if ( noErr() ) {
		flush();					// Write any pending data
		
		if ( noErr() ) {
			CEgIFile::seek( inPos );
			diskSeek( inPos );
		}
	}
}

void CEgIOFile::close() {
	
	if ( is_open() ) {
		flush();
	
		CEgIFile::close();
	}
}
