#ifndef _DAEDEF_H
#define _DAEDEF_H

/*	redirect Asserts in inline code to seem to fire from this file
/**/
#define szAssertFilename	__FILE__

#include "config.h"

/***********************************************************/
/****************** global configuration macros ************/
/***********************************************************/

#define CHECKSUM	 			/* check sum for read/write page validation */
//#define PERFCNT	 			/* enable performance counter */
//#define NO_LOG  				/* log disable */
#define REUSE_DBID	 			/* reuse detached database DBIDs */
//#define CHECK_LOG_VERSION
#define PCACHE_OPTIMIZATION		/* enable all cache optimizations */

#define PREREAD		 			/* try to preread pages when we read in one direction */
#ifdef DEBUG
#ifdef PREREAD
//#define PREREAD_DEBUG
#endif	// PREREAD
#endif	// DEBUG

/***********************************************************/
/******************* declaration macros ********************/
/***********************************************************/

#define VTAPI

#include "daedebug.h"

#ifndef PROFILE
#define LOCAL static
#else
#define LOCAL
#endif


// Hack for OLE-DB - make all functions global and non-inline

#ifdef USE_OLEDB
#undef LOCAL
#undef INLINE
#define LOCAL
#define INLINE
#endif


/***********************************************************/
/************ global types and associated macros ***********/
/***********************************************************/

typedef struct _res			/* resource, defined in sysinit.c and daeutil.h */
	{
	const INT 	cbSize;
	INT			cblockAlloc;
	BYTE 		*pbAlloc;
	INT			cblockAvail;
	BYTE 		*pbAvail;
	INT			iblockCommit;
	INT			iblockFail;
	BYTE		*pbPreferredThreshold;
	} RES;

typedef struct _pib		PIB;
typedef struct _ssib	SSIB;
typedef struct _fucb	FUCB;
typedef struct _csr		CSR;
typedef struct _fcb		FCB;
typedef struct _fdb		FDB;
typedef struct _idb		IDB;
typedef struct _dib		DIB;
typedef struct _rcehead	RCEHEAD;
typedef struct _rce		RCE;
typedef struct _bucket	BUCKET;
typedef struct _dab		DAB;
typedef struct _rmpage	RMPAGE;
typedef struct _bmfix	BMFIX;

typedef unsigned short LANGID;
typedef ULONG			LRID;
typedef ULONG			PROCID;

#define pNil			((void *)0)
#define pbNil			((BYTE *)0)
#define plineNil		((LINE *)0)
#define pkeyNil 		((KEY *)0)
#define ppibNil 		((PIB *)0)
#define pwaitNil		((WAIT *)0)
#define pssibNil		((SSIB *)0)
#define pfucbNil		((FUCB *)0)
#define pcsrNil 		((CSR *)0)
#define pfcbNil 		((FCB *)0)
#define pfdbNil 		((FDB *)0)
#define pfieldNil		((FIELD *)0)
#define pidbNil 		((IDB *)0)
#define pscbNil 		((SCB *)0)
#define procidNil		((PROCID) 0xffff)
#define pbucketNil		((BUCKET *)0)
#define prceheadNil		((RCEHEAD *)0)
#define prceNil			((RCE *)0)
#define pdabNil			((DAB *)0)
#define	prmpageNil		((RMPAGE *) 0)

typedef unsigned long	PGNO;
typedef unsigned long	PGDISCONT;
typedef unsigned long	PN;
#define pnNull			((PN) 0)
#define pgnoNull		((PGNO) 0)

/* UNDONE: should be in storage.h */
#define FVersionPage(pbf)  (pbf->ppage->cVersion)

#define CPG					LONG					/* count of pages */

typedef BYTE				LEVEL;		 		/* transaction levels */
#define levelNil			((LEVEL)0xff)		/*	flag for inactive PIB */

typedef WORD				DBID;
typedef WORD				FID;
typedef SHORT				IDXSEG;

typedef ULONG SRID;
typedef ULONG LINK;

STATIC INLINE PGNO PgnoOfSrid( SRID const srid )
	{
	return srid >> 8;
	}

STATIC INLINE BYTE ItagOfSrid( SRID const srid )
	{
	return *( (BYTE *) &srid );
	}
	
STATIC INLINE SRID SridOfPgnoItag( PGNO const pgno, LONG const itag )
	{
	return (SRID) ( ( pgno << 8 ) | (BYTE) itag );
	}

#define itagNil			( 0x0FFF )
#define sridNull		( 0x000000FF )
#define sridNullLink	( 0 )


/*	position within current series
 *	note order of field is of the essence as log position used by
 *	storage as timestamp, must in ib, isec, lGen order so that we can
 *  use little endian integer comparisons.
 */
typedef struct
	{
	USHORT ib;					/* must be the last so that lgpos can */
	USHORT isec;				/* index of disksec starting logsec	 */
	LONG lGeneration;			/* generation of logsec */
	} LGPOS;					/* be casted to TIME. */

extern LGPOS lgposMax;
extern LGPOS lgposMin;
extern INT fRecovering;			/* to turn off logging during Redo */

#define fRecoveringNone		0
#define fRecoveringRedo		1
#define fRecoveringUndo		2
extern INT fRecoveringMode;		/* where we are in recovering? Redo or Undo phase */

extern char szBaseName[];
extern char szSystemPath[];
extern int  fTempPathSet;
extern char szTempPath[];
extern char szJet[];
extern char szJetLog[];
extern char szJetLogNameTemplate[];
extern char szJetTmp[];
extern char szJetTmpLog[];
extern char szMdbExt[];
extern char szJetTxt[];
	
/***********************************************************/
/*********************** DAE macros ************************/
/***********************************************************/

/*	these are needed for setting columns and tracking indexes
/**/
#define cbitFixed			32
#define cbitVariable		32
#define cbitFixedVariable	(cbitFixed + cbitVariable)
#define cbitTagged			192

#define fidFixedLeast			1
#define fidFixedMost  			(fidVarLeast-1)
#define fidVarLeast				128
#define fidVarMost				(fidTaggedLeast-1)
#define fidTaggedLeast			256
#define fidTaggedMost			(0x7ffe)
#define fidMax					(0x7fff)

#define FFixedFid(fid)			((fid)<=fidFixedMost && (fid)>=fidFixedLeast)
#define FVarFid(fid)			((fid)<=fidVarMost && (fid)>=fidVarLeast)
#define FTaggedFid(fid)			((fid)<=fidTaggedMost && (fid)>=fidTaggedLeast)

STATIC INLINE INT IbFromFid ( FID fid )
	{
	INT ib;
	if ( FFixedFid( fid ) )
		{
		ib = ((fid - fidFixedLeast) % cbitFixed) / 8;
		}
	else if ( FVarFid( fid ) )
		{
		ib = (((fid - fidVarLeast) % cbitVariable) + cbitFixed) / 8;
		}
	else
		{
		Assert( FTaggedFid( fid ) );
		ib = (((fid - fidTaggedLeast) % cbitTagged) + cbitFixedVariable) / 8;
		}
	Assert( ib >= 0 && ib < 32 );
	return ib;
	}

STATIC INLINE INT IbitFromFid ( FID fid )
	{
	INT ibit;
	if ( FFixedFid( fid ) )
		{
		ibit =  1 << ((fid - fidFixedLeast) % 8 );
		}
	else if ( FVarFid( fid ) )
		{
		ibit =  1 << ((fid - fidVarLeast) % 8);
		}
	else
		{
		Assert( FTaggedFid( fid ) );
		ibit =  1 << ((fid - fidTaggedLeast) % 8);
		}
	return ibit;
	}

/*  per database operation counter, qwDBTime is logged, used to compare
 *  with the ulDBTime of a page to decide if a redo of the logged operation
 *  is necessary.
 */
#define qwDBTimeMin	(0x0000000000000000)
#define qwDBTimeMax	(0x0000000fffffffff)

/*  Transaction counter, used to keep track of the oldest transaction.
 */
typedef ULONG		TRX;
#define trxMin		0
#define trxMax		(0xffffffff)

typedef struct
	{
	ULONG cb;
	BYTE *pb;
	} LINE;

STATIC INLINE BOOL FLineNull( LINE const *pline )
	{
	return !pline || !pline->cb || !pline->pb;
	}

STATIC INLINE VOID LineCopy( LINE *plineTo, LINE const *plineFrom )
	{
	plineTo->cb = plineFrom->cb;
	memcpy( plineTo->pb, plineFrom->pb, plineFrom->cb );
	}

STATIC INLINE ULONG CbLine( LINE const *pline )
	{
	return pline ? pline->cb : 0;
	}

typedef LINE KEY;
				
#define FKeyNull					FLineNull
#define KeyCopy						LineCopy
#define CbKey						CbLine

STATIC INLINE BYTE *Pb4ByteAlign( BYTE const *pb )
	{
	return (BYTE *) ( ( (LONG_PTR) pb + 3 ) & ~3 );
	}

STATIC INLINE BYTE *Pb4ByteTruncate( BYTE const *pb )
	{
	return (BYTE *) ( (LONG_PTR) pb & ~3 );
	}
	
typedef struct _threebytes { BYTE b[3]; } THREEBYTES;

/***BEGIN MACHINE DEPENDANT***/
STATIC INLINE VOID ThreeBytesFromL( THREEBYTES *ptb, LONG const l )
	{
	memcpy( ptb, &l, sizeof(THREEBYTES) );
	}

STATIC INLINE VOID LFromThreeBytes( LONG *pl, THREEBYTES *ptb )
	{
	*pl = 0;
	memcpy( pl, ptb, sizeof(THREEBYTES) );
	}

STATIC INLINE VOID KeyFromLong( BYTE *rgbKey, ULONG const ul )
	{
	BYTE *rgbul = (BYTE *) &ul;
	
	rgbKey[3] = rgbul[0];
	rgbKey[2] = rgbul[1];
	rgbKey[1] = rgbul[2];
	rgbKey[0] = rgbul[3];
	}

STATIC INLINE VOID LongFromKey( ULONG *pul, BYTE const *rgbKey )
	{
	BYTE *rgbul = (BYTE *) pul;
	
	rgbul[3] = rgbKey[0];
	rgbul[2] = rgbKey[1];
	rgbul[1] = rgbKey[2];
	rgbul[0] = rgbKey[3];
	}
/***END MACHINE DEPENDANT***/

/***********************************************************/
/******************** general C macros *********************/
/***********************************************************/

#define forever					for(;;)

#define NotUsed(p)				( p==p )

/***********************************************************/
/***** include Jet Project prototypes and constants ********/
/***********************************************************/

#define VOID			void
#define VDBAPI

extern CODECONST(VTFNDEF) vtfndefIsam;
extern CODECONST(VTFNDEF) vtfndefIsamInfo;
extern CODECONST(VTFNDEF) vtfndefTTSortIns;
extern CODECONST(VTFNDEF) vtfndefTTSortRet;
extern CODECONST(VTFNDEF) vtfndefTTBase;

#ifdef DEBUG
JET_TABLEID TableidOfVtid( FUCB *pfucb );
#else
#define TableidOfVtid( pfucb )		( (pfucb)->tableid )
#endif


ERR VTAPI ErrDispPrepareUpdate( JET_SESID sesid, JET_TABLEID tableid,
	JET_GRBIT grbit );
ERR VTAPI ErrDispSetColumn( JET_SESID sesid, JET_TABLEID tableid,
	JET_COLUMNID columnid, const void *pb, unsigned long cb, JET_GRBIT grbit,
	JET_SETINFO *psetinfo );
JET_VSESID UtilGetVSesidOfSesidTableid( JET_SESID sesid, JET_TABLEID tableid );
ERR VTAPI ErrDispCloseTable( JET_SESID sesid, JET_TABLEID tableid );
ERR VTAPI ErrDispUpdate( JET_SESID sesid, JET_TABLEID tableid, void *pb,
	unsigned long cbMax, unsigned long *pcbActual );
ERR VTAPI ErrDispMove( JET_SESID sesid, JET_TABLEID tableid, long crows, JET_GRBIT grbit );

/***********************************************************/
/******************* mutual exclusion **********************/
/***********************************************************/

typedef void * SIG;
typedef void * CRIT;

/*	enable multiple MUTEX resource
/**/
#ifdef SGMUTEX					/* small grain */

#define	ErrSignalCreate( s, sz ) 				ErrUtilSignalCreate( s, sz )
#define	ErrSignalCreateAutoReset( s, sz ) 		ErrUtilSignalCreateAutoReset( s, sz )
#define	SignalReset( s )						UtilSignalReset( s )
#define	SignalSend( s )							UtilSignalSend( s )
#define	SignalWait( s, t ) 						UtilSignalWait( s, t )
#define	SignalWaitEx( s, t, f ) 				UtilSignalWaitEx( s, t, f )
#define	MultipleSignalWait( i, rg, f, t )		UtilMultipleSignalWait( i, rg, f, t )
#define	SignalClose( s )				   		UtilCloseSignal( s )

#define	ErrInitializeCriticalSection( s )  		ErrUtilInitializeCriticalSection( s )
#define	EnterCriticalSection( s ) 				UtilEnterCriticalSection( s )
#define	LeaveCriticalSection( s ) 				UtilLeaveCriticalSection( s )
#define	EnterNestableCriticalSection( s ) 		UtilEnterNestableCriticalSection( s )
#define	LeaveNestableCriticalSection( s )		UtilLeaveNestableCriticalSection( s )
#define	AssertCriticalSection( s )				UtilAssertCrit( s )
#define	AssertNotInCriticalSection( s )			UtilAssertNotInCrit( s )
#define	DeleteCriticalSection( s )				UtilDeleteCriticalSection( s )

#define	LgErrInitializeCriticalSection( s )		JET_errSuccess
#define	LgEnterCriticalSection( s )		  		0
#define	LgLeaveCriticalSection( s )		  		0
#define	LgEnterNestableCriticalSection( s )	  	0
#define	LgLeaveNestableCriticalSection( s )	  	0
#define	LgAssertCriticalSection( s )			0
#define	LgAssertNotInCriticalSection( s )		0
#define	LgDeleteCriticalSection( s )			0
#define HoldCriticalSection( s )				0
#define ReleaseCriticalSection( s )				0

#define	SgErrInitializeCriticalSection			ErrInitalizeCriticalSection
#define	SgEnterCriticalSection				   	EnterCriticalSection
#define	SgLeaveCriticalSection					LeaveCriticalSection
#define	SgEnterNestableCriticalSection		   	EnterNestableCriticalSection
#define	SgLeaveNestableCriticalSection			LeaveNestableCriticalSection
#define	SgAssertCriticalSection			   		AssertCriticalSection
#define	SgAssertNotInCriticalSection			AssertNotInCriticalSection
#define	SgDeleteCriticalSection					DeleteCriticalSection

#else /* !SGMUTEX */

#define	ErrSignalCreate( s, sz ) 			   	ErrUtilSignalCreate( s, sz )
#define	ErrSignalCreateAutoReset( s, sz )		ErrUtilSignalCreateAutoReset( s, sz )
#define	SignalReset( s )					   	UtilSignalReset( s )
#define	SignalSend( s )							UtilSignalSend( s )
#define	SignalWait( s, t ) 						UtilSignalWait( s, t )
#define	SignalWaitEx( s, t, f ) 				UtilSignalWaitEx( s, t, f )
#define	MultipleSignalWait( i, rg, f, t )		UtilMultipleSignalWait( i, rg, f, t )
#define	SignalClose( s )						UtilCloseSignal( s )
#define	ErrInitializeCriticalSection( s )		ErrUtilInitializeCriticalSection( s )
#define	EnterCriticalSection( s )				UtilEnterCriticalSection( s )
#define	LeaveCriticalSection( s )				UtilLeaveCriticalSection( s )
#define	EnterNestableCriticalSection( s ) 		UtilEnterNestableCriticalSection( s )
#define	LeaveNestableCriticalSection( s ) 		UtilLeaveNestableCriticalSection( s )
#define	AssertCriticalSection( s )				UtilAssertCrit( s )
#define	AssertNotInCriticalSection( s )			UtilAssertNotInCrit( s )
#define	DeleteCriticalSection( s )				UtilDeleteCriticalSection( s )

#define	LgErrInitializeCriticalSection			ErrUtilInitializeCriticalSection
#define	LgEnterCriticalSection					UtilEnterCriticalSection
#define	LgLeaveCriticalSection					UtilLeaveCriticalSection
#define	LgEnterNestableCriticalSection			UtilEnterNestableCriticalSection
#define	LgLeaveNestableCriticalSection			UtilLeaveNestableCriticalSection
#define	LgAssertCriticalSection					UtilAssertCrit
#define	LgAssertNotInCriticalSection			UtilAssertNotInCrit
#define	LgDeleteCriticalSection					UtilDeleteCriticalSection
#define LgHoldCriticalSection( s )		\
	{									\
	UtilAssertCrit( s );				\
	UtilHoldCriticalSection( s );		\
	}
#define LgReleaseCriticalSection( s )	\
	{									\
	UtilAssertCrit( s );				\
	UtilReleaseCriticalSection( s );	\
	}

#define	SgErrInitializeCriticalSection( s )		JET_errSuccess
#define	SgEnterCriticalSection( s )		  		0
#define	SgLeaveCriticalSection( s )		  		0
#define	SgEnterNestableCriticalSection( s )	  	0
#define	SgLeaveNestableCriticalSection( s )	  	0
#define	SgAssertCriticalSection( s )			0
#define	SgAssertNotInCriticalSection( s )		0
#define	SgDeleteCriticalSection( s )			0

#endif /* !SGMUTEX */

/*	include other global DAE headers
/**/
#include	"daeconst.h"

#define	fSTInitNotDone		0
#define fSTInitInProgress 	1
#define	fSTInitDone			2
extern BOOL  fSTInit;

#pragma pack(1)
typedef struct
	{
	ULONG	cDiscont;
	ULONG	cUnfixedMessyPage;
	} P_OLC_DATA;


#define MAX_COMPUTERNAME_LENGTH 15

typedef struct
	{
	BYTE		bSeconds;				//	0 - 60
	BYTE		bMinutes;				//	0 - 60
	BYTE		bHours;					//	0 - 24
	BYTE		bDay;					//	1 - 31
	BYTE		bMonth;					//	0 - 11
	BYTE		bYear;					//	current year - 1900
	BYTE		bFiller1;
	BYTE		bFiller2;
	} LOGTIME;

typedef struct _signiture
	{
	ULONG		ulRandom;			/*	a random number */
	LOGTIME		logtimeCreate;		/*	time db created, in logtime format */
	BYTE		szComputerName[ MAX_COMPUTERNAME_LENGTH + 1 ];	/* where db is created */
	} SIGNATURE;

typedef struct _bkinfo
	{
	LGPOS		lgposMark;			/*	id for this backup */
	LOGTIME		logtimeMark;
	ULONG		genLow;
	ULONG		genHigh;
	} BKINFO;

/*	Magic number used in database header for integrity checking
/**/
#define ulDAEMagic					0x89abcdef
#define ulDAEVersion				0x00000500
#define ulDAEPrevVersion			0x00000400	/* temporary to make exchange compatible */

#define fDBStateJustCreated			1
#define fDBStateInconsistent		2
#define fDBStateConsistent			3

typedef struct _dbfilehdr_fixed
	{
	ULONG		ulChecksum;		/*	checksum of the 4k page						*/
	ULONG		ulMagic;		/*	Magic number								*/
	ULONG		ulVersion;		/*	version of DAE the db created				*/
	SIGNATURE	signDb;			/*	signature of the db (incl. creation time).	*/

	ULONG		grbitAttributes;/*	attributes of the db						*/
	
	ULONG		ulDBTimeLow;	/*	low ulDBTime of this database				*/
								/*	keep it here for backward compatibility		*/

	ULONG		fDBState;		/*	consistent/inconsistent state				*/
	
	LGPOS		lgposConsistent;/*	null if in inconsistent state				*/
	LOGTIME		logtimeConsistent;/* null if in inconsistent state				*/

	LOGTIME		logtimeAttach;	/*	Last attach time.							*/
	LGPOS		lgposAttach;

	LOGTIME		logtimeDetach;	/*	Last detach time.							*/
	LGPOS		lgposDetach;

	DBID		dbid;			/*	current db attachment.						*/
	SIGNATURE	signLog;		/*	log signature for this attachments			*/

	BKINFO		bkinfoFullPrev;	/*	Last successful full backup.				*/

	BKINFO		bkinfoIncPrev;	/*	Last successful Incremental backup.			*/
								/*	Reset when bkinfoFullPrev is set			*/
	BKINFO		bkinfoFullCur;	/*	current backup. Succeed if a				*/
								/*	corresponding pat file generated.			*/

	ULONG		ulDBTimeHigh;	/*	DBTime										*/

	} DBFILEHDR_FIXED;


#define cbPage	 		4096	 	// database logical page size

typedef struct _dbfilehdr
	{
	DBFILEHDR_FIXED;
	BYTE		rgbFiller[ cbPage - sizeof( DBFILEHDR_FIXED ) ];
	} DBFILEHDR;

#pragma pack()

STATIC INLINE VOID DBHDRSetDBTime( DBFILEHDR *pdbfilehdr, QWORD qwDBTime )
	{
	QWORDX qwx;
	qwx.qw = qwDBTime;
	pdbfilehdr->ulDBTimeLow = qwx.l;
	pdbfilehdr->ulDBTimeHigh = qwx.h;
	}

STATIC INLINE QWORD QwDBHDRDBTime( DBFILEHDR *pdbfilehdr )
	{
	QWORDX qwx;
	qwx.l = pdbfilehdr->ulDBTimeLow;
	qwx.h = pdbfilehdr->ulDBTimeHigh;
	return qwx.qw;
	}

// #define TEST_WRAP_AROUND	1

STATIC INLINE VOID DBHDRIncDBTime( DBFILEHDR *pdbfilehdr )
	{
	QWORD qw;
	qw = QwDBHDRDBTime( pdbfilehdr );
#ifdef TEST_WRAP_AROUND
	if ( qw < 0x00000000fffc0000 )
		qw = 0x00000000fffc0000;
#endif
	qw++;
	DBHDRSetDBTime( pdbfilehdr, qw );
	}

#undef szAssertFilename

#endif  // _DAEDEF_H