//-----------------------------------------------------------------------------
//
//  $Logfile:: /Quake 2 Engine/Sin/code/game/archive.h                        $
// $Revision:: 9                                                              $
//   $Author:: Jimdose                                                        $
//     $Date:: 11/12/98 2:31a                                                 $
//
// Copyright (C) 1997 by Ritual Entertainment, Inc.
// All rights reserved.
//
// This source is may not be distributed and/or modified without
// expressly written permission by Ritual Entertainment, Inc.
//
// $Log:: /Quake 2 Engine/Sin/code/game/archive.h                             $
//
// 9     11/12/98 2:31a Jimdose
// Added ReadFile.  Archives now read from pak files
//
// 8     10/25/98 11:52p Jimdose
// added EXPORT_TEMPLATE
//
// 7     10/07/98 11:41p Jimdose
// Got savegames working!!!
// Rewrote event archiving
//
// 6     9/21/98 10:15p Markd
// Putting archiving and unarchiving functions in
//
// 5     9/21/98 4:21p Markd
// Put in archive functions and rewrote all archive routines
//
// 4     5/24/98 4:48p Jimdose
// Made char *'s const
//
// 3     5/08/98 2:50p Jimdose
// Base archivable class is now Class instead of Listener
//
// 2     5/07/98 10:39p Jimdose
// created file
//
// 1     5/06/98 8:19p Jimdose
//
// DESCRIPTION:
// Class for archiving objects
//

#ifndef __ARCHIVE_H__
#define __ARCHIVE_H__

#include "g_local.h"
#include "str.h"

#define ARCHIVE_NULL_POINTER ( -654321 )
#define ARCHIVE_POINTER_VALID ( 0 )
#define ARCHIVE_POINTER_NULL ( ARCHIVE_NULL_POINTER )
#define ARCHIVE_POINTER_SELF_REFERENTIAL ( -123456 )

enum
{
	pointer_fixup_normal,
	pointer_fixup_safe
};

typedef struct
{
	void** ptr;
	int index;
	int type;
} pointer_fixup_t;

class ReadFile : public Class
{
protected:
	str filename;
	size_t length;
	byte*           buffer;
	byte*           pos;

public:
	CLASS_PROTOTYPE( ReadFile );

	ReadFile();
	~ReadFile();
	void                Close( void );
	const char*     Filename( void );
	size_t         Length( void );
	size_t         Pos( void );
	qboolean       Seek( size_t newpos );
	qboolean       Open( const char* name );
	qboolean       Read( void* dest, size_t size );
};

class Archiver : public Class
{
private:
	Container<Class*>         classpointerList;
	Container<pointer_fixup_t*> fixupList;

protected:
	str filename;
	qboolean fileerror;
	FILE*               file;
	ReadFile readfile;
	int archivemode;
	int numclassespos;

	void                CheckRead( void );
	void                CheckType( int type );
	int            ReadType( void );
	unsigned          ReadSize( void ); /* was size_t */
	void                CheckSize( int type, size_t size );
	void                ReadData( int type, void* data, size_t size );

	void                CheckWrite( void );
	void                WriteType( int type );
	void                WriteSize( unsigned int size );/* was size_t -- changed for 64 bit compatibility */
	void                WriteData( int type, const void* data, unsigned int size );/* was size_t -- changed for 64 bit compatibility */

public:
	CLASS_PROTOTYPE( Archiver );

	Archiver();
	~Archiver();
	void                FileError( const char* fmt, ... ) __attribute__((__noreturn__, __format__(__printf__,2,3)));
								/* Note about printf format attribute argument # :
								 * http://stackoverflow.com/questions/11621043 :
								 * non-static member functions treat 'this' as #1 */
	void                Close( void );

	void                Read( str& name );
	void                Read( const char* name );

	//
	// return methods
	//
	Vector          ReadVector( void );
	Quat               ReadQuat( void );
	int             ReadInteger( void );
	unsigned            ReadUnsigned( void );
	byte                ReadByte( void );
	char                ReadChar( void );
	short               ReadShort( void );
	unsigned short  ReadUnsignedShort( void );
	float               ReadFloat( void );
	double          ReadDouble( void );
	qboolean            ReadBoolean( void );
	str             ReadString( void );
	Event           ReadEvent( void );
	//
	// ptr methods
	//
	void            ReadVector( Vector* vec );
	void            ReadQuat( Quat* quat );
	void                ReadInteger( int* num );
	void            ReadUnsigned( unsigned* unum );
	void                ReadByte( byte* num );
	void                ReadChar( char* ch );
	void                ReadShort( short* num );
	void           ReadUnsignedShort( unsigned short* num );
	void           ReadFloat( float* num );
	void               ReadDouble( double* num );
	void            ReadBoolean( qboolean* bBool );
	void            ReadString( str* string );
	void           ReadObjectPointer( Class** ptr );
	void           ReadSafePointer( SafePtrBase* ptr );
	void           ReadEvent( Event* ev );

	void                ReadRaw( void* data, size_t size );
	Class*              ReadObject( void );
	Class*              ReadObject( Class* obj );

	void                Create( str& name );
	void                Create( const char* name );
	void                WriteVector( const Vector& v );
	void                WriteQuat( const Quat& quat );
	void                WriteInteger( int v );
	void                WriteUnsigned( unsigned v );
	void                WriteByte( byte v );
	void                WriteChar( char v );
	void                WriteShort( short v );
	void                WriteUnsignedShort( unsigned short v );
	void                WriteFloat( float v );
	void                WriteDouble( double v );
	void                WriteBoolean( qboolean v );
	void                WriteRaw( const void* data, unsigned int size );/* was size_t -- changed for 64 bit compatibility */
	void                WriteString( const str& string );
	void                WriteObject( Class* obj );
	void           WriteObjectPointer( Class* ptr );
	void           WriteSafePointer( Class* ptr );
	void           WriteEvent( Event& ev );
	void           WriteEvent( Event* ev );
};

inline void Archiver::Read( str& name )
{
	Read( name.c_str() );
}

inline void Archiver::Create( str& name )
{
	Create( name.c_str() );
}

#endif /* archive.h */
