/****************************************************************************
Desc:
****************************************************************************/
void flmDbgLogExit( void)
{
	if( g_bDbgLogEnabled)
	{
		// Output "Log End" message
		f_mutexLock( g_hDbgLogMutex);
		_flmDbgOutputMsg( "--- LOG END ---");
		f_mutexUnlock( g_hDbgLogMutex);
		
		// Flush the log
		flmDbgLogFlush();
	}

	// Free all resources

	if( g_hDbgLogMutex != F_MUTEX_NULL)
	{
		f_mutexDestroy( &g_hDbgLogMutex);
	}

	if( g_pszLogBuf)
	{
		f_free( &g_pszLogBuf);
	}

	if( g_pLogFile)
	{
		g_pLogFile->Truncate( g_uiLogFileOffset + g_uiLogBufOffset);
		g_pLogFile->Close();
		g_pLogFile->Release();
		g_pLogFile = NULL;
	}

	g_bDbgLogEnabled = FALSE;
}
/****************************************************************************
Desc:
****************************************************************************/
void FLMAPI f_rwlockDestroy(
	F_RWLOCK *			phReadWriteLock)
{
	F_RWLOCK_IMP *		pReadWriteLock = (F_RWLOCK_IMP *)*phReadWriteLock;
	
	if( pReadWriteLock)
	{
		f_assert( !pReadWriteLock->pNotifyList);
		
		if( pReadWriteLock->hMutex != F_MUTEX_NULL)
		{
			f_mutexDestroy( &pReadWriteLock->hMutex);
		}
		
		f_free( &pReadWriteLock);
	}
}
/****************************************************************************
Desc:
****************************************************************************/
F_IOBufferMgr::~F_IOBufferMgr()
{
	f_assert( !m_pFirstPending);
	f_assert( !m_pFirstUsed);
	f_assert( !m_pAvailNotify);
	
	while( m_pFirstAvail)
	{
		m_pFirstAvail->Release();
	}
	
	if( m_hMutex != F_MUTEX_NULL)
	{
		f_mutexDestroy( &m_hMutex);
	}
	
#if !defined( FLM_UNIX) && !defined( FLM_NLM)
	if( m_hAvailSem != F_SEM_NULL)
	{
		f_semDestroy( &m_hAvailSem);
	}
#endif
}
/****************************************************************************
Desc:	This destructor frees all of the structures associated with an
		F_Database object.
		Whoever called this routine has already determined that it is safe
		to do so.
Notes:	The global mutex is assumed to be locked when entering the
			routine.  It may be unlocked and re-locked before the routine
			exits, however.
****************************************************************************/
F_Database::~F_Database()
{
	F_NOTIFY_LIST_ITEM *	pCloseNotifies;
	F_Dict *    			pDict;
	F_Dict *					pTmpDict;

	// At this point, the use count better be zero

	flmAssert( !m_uiOpenIFDbCount);

	// Shut down all background threads before shutting down the CP thread.

	shutdownDatabaseThreads();

	if (m_pRfl)
	{
		m_pRfl->closeFile();
	}

	// Shouldn't have any pending input at this point

	flmAssert( !m_pPendingInput);

	// At this point, the use count better be zero

	flmAssert( !m_uiOpenIFDbCount);

	// Unlock the mutex

	f_mutexUnlock( gv_XFlmSysData.hShareMutex);

	// Shut down the checkpoint thread

	if( m_pCPThrd)
	{
		m_pCPThrd->stopThread();
		m_pCPThrd->Release();
		m_pCPThrd = NULL;
	}

	// Unlink all of the F_Dict objects that are connected to the
	// database.

	lockMutex();
	while (m_pDictList)
	{
		m_pDictList->unlinkFromDatabase();
	}
	unlockMutex();

	// Take the file out of its name hash bucket, if any.

	if (m_uiBucket != 0xFFFF)
	{
		f_mutexLock( gv_XFlmSysData.hShareMutex);
		if (m_pPrev)
		{
			m_pPrev->m_pNext = m_pNext;
		}
		else
		{
			gv_XFlmSysData.pDatabaseHashTbl[ m_uiBucket].pFirstInBucket = m_pNext;
		}

		if (m_pNext)
		{
			m_pNext->m_pPrev = m_pPrev;
		}
		m_uiBucket = 0xFFFF;
		
		// After this point, we should not need to keep the global mutex locked
		// because the F_Database is no longer visible to any thread to find in
		// the hash table.
	
		f_mutexUnlock( gv_XFlmSysData.hShareMutex);
	}
	
	// Shouldn't have any queries at this point.  But we will be nice in case
	// we do and will unlink the queries from the list

	flmAssert( !m_pFirstQuery);
	while (m_pFirstQuery)
	{
		F_Query *	pQuery = m_pFirstQuery;

		m_pFirstQuery = m_pFirstQuery->m_pNext;
		pQuery->m_pPrev = NULL;
		pQuery->m_pNext = NULL;
		pQuery->m_pDatabase = NULL;
	}

	// Free the RFL data, if any.

	if (m_pRfl)
	{
		m_pRfl->Release();
		m_pRfl = NULL;
	}

	flmAssert( m_pOpenNotifies == NULL);
	m_pOpenNotifies = NULL;

	// Save pCloseNotifies -- we will notify any waiters once the
	// F_Database has been freed.

	pCloseNotifies = m_pCloseNotifies;

	// Free any dictionary usage structures associated with the database.

	pDict = m_pDictList;
	while (pDict)
	{
		pTmpDict = pDict;
		pDict = pDict->getNext();
		pTmpDict->Release();
	}
	m_pDictList = NULL;

	// Free any shared cache associated with the database.
	// IMPORTANT NOTE:
	// Cannot have the global mutex locked when these are called because
	// these routines lock the block cache mutex and the node cache mutex.
	// If both the global mutex and the block or node cache mutexes are to be
	// locked, the rule is that the block or node cache mutex must be locked
	// before locking the global mutex.  This is because neededByReadTrans
	// will end up doing it in this order - when neededByReadTrans is called
	// either the block or node cache mutex is already locked, and it will
	// additionally lock the global mutex.  Since that order is already
	// required, we cannot have anyone else attempting to lock the mutexes
	// in a different order.
	
	freeBlockCache();
	freeNodeCache();
	
	// Release the lock objects.

	if (m_pWriteLockObj)
	{
		m_pWriteLockObj->Release();
		m_pWriteLockObj = NULL;
	}

	if (m_pDatabaseLockObj)
	{
		m_pDatabaseLockObj->Release();
		m_pDatabaseLockObj = NULL;
	}

	// Close and delete the lock file.

	if (m_pLockFileHdl)
	{
		(void)m_pLockFileHdl->closeFile();
		m_pLockFileHdl->Release();
		m_pLockFileHdl = NULL;
	}

	// Free the write buffer managers.

	if (m_pBufferMgr)
	{
		m_pBufferMgr->Release();
		m_pBufferMgr = NULL;
	}
	
	// Free the log header write buffer

	if (m_pDbHdrWriteBuf)
	{
		f_freeAlignedBuffer( (void **)&m_pDbHdrWriteBuf);
	}

	// Free the update buffer

	if (m_pucUpdBuffer)
	{
		f_free( &m_pucUpdBuffer);
		m_uiUpdBufferSize = 0;
	}
	
	m_krefPool.poolFree();

	if (m_ppBlocksDone)
	{
		f_free( &m_ppBlocksDone);
		m_uiBlocksDoneArraySize = 0;
	}

	// Notify waiters that the F_Database is gone

	while (pCloseNotifies)
	{
		F_SEM		hSem;

		*(pCloseNotifies->pRc) = NE_XFLM_OK;
		hSem = pCloseNotifies->hSem;
		pCloseNotifies = pCloseNotifies->pNext;
		f_semSignal( hSem);
	}

	f_free( &m_pszDbPath);
	
	// Encryption stuff
	
	if (m_pszDbPasswd)
	{
		f_free( &m_pszDbPasswd);
	}
	
	if (m_pWrappingKey)
	{
		m_pWrappingKey->Release();
		m_pWrappingKey = NULL;
	}
	
	flmAssert( !m_pFirstNode && !m_pLastNode && !m_pLastDirtyNode);
	
	if (m_hMutex != F_MUTEX_NULL)
	{
		f_mutexDestroy( &m_hMutex);
	}
	
	// Global mutex is still expected to be locked at this point
	
	f_mutexLock( gv_XFlmSysData.hShareMutex);
}
int __cdecl main(
	int			iArgC,
	char **		ppszArgV)
#endif   
{
	int			iRetCode = 0;

	gigaInitGlobalVars();

#ifdef FLM_NLM

	// Setup the routines to be called when the NLM exits itself
	
	atexit( gigaCleanup);

#endif

	if( RC_BAD( FlmStartup()))
	{
		iRetCode = 1;
		goto Exit;
	}

	if( RC_BAD( FTXInit( gv_pszTitle, (FLMBYTE)80, (FLMBYTE)50,
					FLM_BLUE, FLM_LIGHTGRAY, NULL, NULL)))
	{
		iRetCode = 1;
		goto Exit;
	}

	FTXSetShutdownFlag( &gv_bShutdown);

	if( RC_BAD( FTXScreenInit( gv_pszTitle, &gv_pScreen)))
	{
		iRetCode = 1;
		goto Exit;
	}

	if( RC_BAD( FTXScreenInitStandardWindows( gv_pScreen, FLM_RED, FLM_WHITE,
		FLM_BLUE, FLM_WHITE, FALSE, TRUE, gv_pszTitle, NULL, &gv_pWindow)))
	{
		iRetCode = 1;
		goto Exit;
	}
	
	FTXWinGetCanvasSize( gv_pWindow, &gv_uiNumCols, &gv_uiNumRows);

	if( RC_BAD( f_mutexCreate( &gv_hWindowMutex)))
	{
		iRetCode = 99;
		goto Exit;
	}

	if( !gigaGetParams( iArgC, (const char **)ppszArgV))
	{
		iRetCode = 2;
		goto Exit;
	}

	f_pathReduce( gv_szDibName, gv_szDirectoryPath, gv_pszFileName);
	if( !gv_szDirectoryPath [0])
	{
		f_strcpy( gv_szDirectoryPath, ".");
	}
	
	if( RC_BAD( gigaLoadDatabase()))
	{
		iRetCode = 7;
		goto Exit;
	}

	if( !gv_bBatchMode)
	{
		gigaOutputErrMsg( "Load complete");
	}

Exit:

	if( gv_hWindowMutex != F_MUTEX_NULL)
	{
		f_mutexDestroy( &gv_hWindowMutex);
	}
	
	FTXExit();
	FlmShutdown();

#ifdef FLM_NLM
	if (!gv_bSynchronized)
	{
		SynchronizeStart();
		gv_bSynchronized = TRUE;
	}
#endif

	gv_bRunning = FALSE;
	return( iRetCode);
}
/****************************************************************************
Name:	flstIndexManagerThread
Desc:	Thread that displays the current status of all indexes in a database
Note:	The caller must open the database and pass a handle to the thread.
		The handle will be closed when the thread exits.
*****************************************************************************/
RCODE FTKAPI flstIndexManagerThread(
	IF_Thread *		pThread)
{
	RCODE						rc = NE_XFLM_OK;
	F_DynamicList *		pList = f_new F_DynamicList;
	FTX_WINDOW *			pTitleWin;
	FTX_WINDOW *			pListWin;
	FTX_WINDOW *			pHeaderWin;
	FTX_WINDOW *			pMsgWin;
	FLMUINT					uiIterations = 0;
	FLMUINT					uiScreenCols;
	FLMUINT					uiScreenRows;
	FLMUINT					uiIndex;
	FLMUINT					uiUpdateInterval;
	FLMUINT					uiLastUpdateTime;
	IX_DISPLAY_INFO		IxDispInfo;
	IX_DISPLAY_INFO *		pDispInfo;
	DLIST_NODE *			pTmpNd;
	FLMUINT					uiKey;
	FLMBOOL					bShowOnline = TRUE;
	F_Db *					pDb = (F_Db *)pThread->getParm1();
	FLMUINT					uiOneSec;
	FLMBOOL					bScreenLocked = FALSE;
	IX_Event					event;
	FLMBOOL					bRegisteredForEvent = FALSE;
	IF_DbSystem *			pDbSystem = NULL;

	event.setDispInfo( &IxDispInfo);

#define FIMT_TITLE_HEIGHT		1
#define FIMT_HEADER_HEIGHT		4
#define FIMT_LOG_HEIGHT			10

	f_memset( &IxDispInfo, 0, sizeof( IX_DISPLAY_INFO));
	IxDispInfo.hScreenMutex = F_MUTEX_NULL;
	IxDispInfo.pDb = (F_Db *)pDb;
	IxDispInfo.bShowTime = TRUE;

	if( RC_BAD( f_mutexCreate( &IxDispInfo.hScreenMutex)))
	{
		goto Exit;
	}

	if( RC_BAD( FTXScreenInit( "Index Manager", &IxDispInfo.pScreen)))
	{
		goto Exit;
	}

	FTXScreenGetSize( IxDispInfo.pScreen, &uiScreenCols, &uiScreenRows);
	FTXScreenDisplay( IxDispInfo.pScreen);

	if( RC_BAD( FTXWinInit( IxDispInfo.pScreen, 0,
		FIMT_TITLE_HEIGHT, &pTitleWin)))
	{
		goto Exit;
	}

	FTXWinSetBackFore( pTitleWin, FLM_RED, FLM_WHITE);
	FTXWinClear( pTitleWin);
	FTXWinPrintStr( pTitleWin, "FLAIM Index Manager");
	FTXWinSetCursorType( pTitleWin, FLM_CURSOR_INVISIBLE);
	FTXWinOpen( pTitleWin);

	if( RC_BAD( FTXWinInit( IxDispInfo.pScreen,
		uiScreenCols, FIMT_HEADER_HEIGHT,
		&pHeaderWin)))
	{
		goto Exit;
	}

	FTXWinMove( pHeaderWin, 0, FIMT_TITLE_HEIGHT);
	FTXWinSetBackFore( pHeaderWin, FLM_BLUE, FLM_WHITE);
	FTXWinClear( pHeaderWin);
	FTXWinSetCursorType( pHeaderWin, FLM_CURSOR_INVISIBLE);
	FTXWinSetScroll( pHeaderWin, FALSE);
	FTXWinSetLineWrap( pHeaderWin, FALSE);
	FTXWinOpen( pHeaderWin);

	if( RC_BAD( FTXWinInit( IxDispInfo.pScreen, uiScreenCols,
		uiScreenRows - FIMT_TITLE_HEIGHT - FIMT_HEADER_HEIGHT - FIMT_LOG_HEIGHT,
		&pListWin)))
	{
		goto Exit;
	}
	FTXWinMove( pListWin, 0, FIMT_TITLE_HEIGHT + FIMT_HEADER_HEIGHT);
	FTXWinOpen( pListWin);
	pList->setup( pListWin);

	if( RC_BAD( FTXWinInit( IxDispInfo.pScreen, uiScreenCols, FIMT_LOG_HEIGHT,
		&IxDispInfo.pLogWin)))
	{
		goto Exit;
	}

	FTXWinDrawBorder( IxDispInfo.pLogWin);
	FTXWinMove( IxDispInfo.pLogWin, 0, uiScreenRows - FIMT_LOG_HEIGHT);
	FTXWinSetBackFore( IxDispInfo.pLogWin, FLM_BLUE, FLM_WHITE);
	FTXWinClear( IxDispInfo.pLogWin);
	FTXWinSetCursorType( IxDispInfo.pLogWin, FLM_CURSOR_INVISIBLE);
	FTXWinSetScroll( IxDispInfo.pLogWin, TRUE);
	FTXWinSetLineWrap( IxDispInfo.pLogWin, FALSE);
	FTXWinOpen( IxDispInfo.pLogWin);
	
	if( RC_BAD( rc = FlmAllocDbSystem( &pDbSystem)))
	{
		goto Exit;
	}

	if (RC_BAD( rc = pDbSystem->registerForEvent(
		XFLM_EVENT_UPDATES, &event)))
	{
		goto Exit;
	}
	bRegisteredForEvent = TRUE;

	FTXWinSetFocus( pListWin);
	uiIterations = 0;
	uiUpdateInterval = FLM_SECS_TO_TIMER_UNITS( 1);
	uiOneSec = FLM_SECS_TO_TIMER_UNITS( 1);
	uiLastUpdateTime = 0;
	while( !gv_bShutdown)
	{
		FLMUINT	uiCurrTime = FLM_GET_TIMER();

		if( bScreenLocked)
		{
			f_mutexUnlock( IxDispInfo.hScreenMutex);
			bScreenLocked = FALSE;
		}

		if( FLM_ELAPSED_TIME( uiCurrTime, uiLastUpdateTime) >= uiUpdateInterval)
		{
Update_Screen:

			if( !bScreenLocked)
			{
				f_mutexLock( IxDispInfo.hScreenMutex);
				bScreenLocked = TRUE;
			}

			FTXWinSetCursorPos( pHeaderWin, 0, 1);
			if( IxDispInfo.bShowTime)
			{
				FTXWinPrintf( pHeaderWin, "Index Index           State Last       Rate       Keys       Documents  Time");
			}
			else
			{
				FTXWinPrintf( pHeaderWin, "Index Index           State Last       Rate       Keys       Documents  Trans");
			}
			FTXWinClearToEOL( pHeaderWin);
			FTXWinPrintf( pHeaderWin, "\n");
			FTXWinPrintf( pHeaderWin, "Num.  Name                  DOC");

			if (RC_BAD( rc = pDb->transBegin( XFLM_READ_TRANS)))
			{
				goto Exit;
			}

			pTmpNd = pList->getFirst();
			uiIndex = 0;
			for( ;;)
			{
				if( RC_BAD( pDb->indexGetNext( &uiIndex)))
				{
					break;
				}

				// Remove all invalid entries

				while( pTmpNd && pTmpNd->uiKey < uiIndex)
				{
					uiKey = pTmpNd->uiKey;
					pTmpNd = pTmpNd->pNext;
					pList->remove( uiKey);
				}

				if (RC_BAD( rc = pDb->indexStatus( uiIndex, &IxDispInfo.IndexStatus)))
				{
					goto Exit;
				}

				if( !bShowOnline &&
					IxDispInfo.IndexStatus.eState == XFLM_INDEX_ONLINE)
				{
					if( pTmpNd && pTmpNd->uiKey == uiIndex)
					{
						uiKey = pTmpNd->uiKey;
						pTmpNd = pTmpNd->pNext;
						pList->remove( uiKey);
					}
					continue;
				}

				if( pTmpNd && pTmpNd->uiKey == uiIndex)
				{
					FLMUINT	uiOldest;
					FLMUINT	uiElapsed;

					pDispInfo = (IX_DISPLAY_INFO *)pTmpNd->pvData;
					f_strcpy( IxDispInfo.szName, pDispInfo->szName);

					// Copy the saved information.

					f_memcpy( &IxDispInfo.ui64SaveDocsProcessed [0],
								&pDispInfo->ui64SaveDocsProcessed [0],
								sizeof( FLMUINT) * MAX_VALS_TO_SAVE);
					f_memcpy( &IxDispInfo.uiDocSaveTime [0],
								&pDispInfo->uiDocSaveTime [0],
								sizeof( FLMUINT) * MAX_VALS_TO_SAVE);
					uiOldest = IxDispInfo.uiOldestSaved = pDispInfo->uiOldestSaved;

					// Recalculate the indexing rate.

					uiCurrTime = FLM_GET_TIMER();
					uiElapsed = (uiCurrTime - IxDispInfo.uiDocSaveTime [uiOldest]) /
															uiOneSec;
					if (uiElapsed && IxDispInfo.IndexStatus.ui64DocumentsProcessed)
					{
						if( IxDispInfo.ui64SaveDocsProcessed[ uiOldest] <
							IxDispInfo.IndexStatus.ui64DocumentsProcessed)
						{
							IxDispInfo.uiIndexingRate =
										// Records processed in time period
										(FLMUINT)((IxDispInfo.IndexStatus.ui64DocumentsProcessed -
										 IxDispInfo.ui64SaveDocsProcessed [uiOldest]) / uiElapsed);
						}
						else
						{
							IxDispInfo.uiIndexingRate = 0;
						}
					}
					else
					{
						IxDispInfo.uiIndexingRate = 0;
					}

					// Overwrite the oldest with the current data.

					IxDispInfo.uiDocSaveTime [uiOldest] = uiCurrTime;
					IxDispInfo.ui64SaveDocsProcessed [uiOldest] =
							IxDispInfo.IndexStatus.ui64DocumentsProcessed;

					// Move oldest pointer for next update.

					if (++IxDispInfo.uiOldestSaved == MAX_VALS_TO_SAVE)
					{
						IxDispInfo.uiOldestSaved = 0;
					}
				}
				else
				{
					FLMUINT			uiLoop;
					FLMUINT			uiBufLen;
					F_DataVector	srchKey;

					uiCurrTime = FLM_GET_TIMER();
					IxDispInfo.uiIndexingRate = 0;
					for (uiLoop = 0; uiLoop < MAX_VALS_TO_SAVE; uiLoop++)
					{
						IxDispInfo.ui64SaveDocsProcessed [uiLoop] =
								IxDispInfo.IndexStatus.ui64DocumentsProcessed;
						IxDispInfo.uiDocSaveTime [uiLoop] = uiCurrTime;
					}
					IxDispInfo.uiOldestSaved = 0;

					// Retrieve index name

					if (RC_BAD( srchKey.setUINT( 0, ELM_INDEX_TAG)))
					{
						break;
					}
					if (RC_BAD( srchKey.setUINT( 1, uiIndex)))
					{
						break;
					}

					if (RC_BAD( rc = pDb->keyRetrieve( XFLM_DICT_NUMBER_INDEX,
											&srchKey, XFLM_EXACT, &srchKey)))
					{
						if (rc != NE_XFLM_NOT_FOUND)
						{
							break;
						}
					}
					else
					{
						F_DOMNode *	pNode = NULL;

						if (RC_BAD( rc = pDb->getNode( XFLM_DICT_COLLECTION,
													srchKey.getDocumentID(), &pNode)))
						{
							if (rc != NE_XFLM_DOM_NODE_NOT_FOUND)
							{
								break;
							}
						}
						else
						{
							uiBufLen = sizeof( IxDispInfo.szName);
							rc = pNode->getAttributeValueUTF8( pDb,
									ATTR_NAME_TAG, (FLMBYTE *)IxDispInfo.szName, uiBufLen);
							pNode->Release();
							if (rc != NE_XFLM_OK &&
								 rc != NE_XFLM_DOM_NODE_NOT_FOUND &&
								 rc != NE_XFLM_CONV_DEST_OVERFLOW)
							{
								break;
							}
						}
					}
				}

				pList->update( uiIndex, ixDisplayHook, &IxDispInfo, sizeof( IxDispInfo));
				pList->refresh();

				if( pTmpNd && pTmpNd->uiKey == uiIndex)
				{
					pTmpNd = pTmpNd->pNext;
				}
			}
			pDb->transAbort();
			uiLastUpdateTime = FLM_GET_TIMER();
			pList->refresh();
		}

		if( !bScreenLocked)
		{
			f_mutexLock( IxDispInfo.hScreenMutex);
			bScreenLocked = TRUE;
		}

		if( RC_OK( FTXWinTestKB( pListWin)))
		{
			FLMUINT		uiChar;

			FTXWinInputChar( pListWin, &uiChar);
			f_mutexUnlock( IxDispInfo.hScreenMutex);
			bScreenLocked = FALSE;

			switch( uiChar)
			{
				case 'O':
				case 'o':
				{
					bShowOnline = !bShowOnline;
					goto Update_Screen;
				}

				case '+':
				case 'r':
				{
					if( (pTmpNd = pList->getCurrent()) != NULL)
					{
						if (RC_BAD( rc = pDb->indexResume( pTmpNd->uiKey)))
						{
							goto Exit;
						}
						goto Update_Screen;
					}
					break;
				}

				case 's':
				{
					if( (pTmpNd = pList->getCurrent()) != NULL)
					{
						if (RC_BAD( rc = pDb->indexSuspend( pTmpNd->uiKey)))
						{
							goto Exit;
						}
						goto Update_Screen;
					}
					break;
				}

				case FKB_ALT_S:
				case 'S':
				{
					f_mutexLock( IxDispInfo.hScreenMutex);
					FTXMessageWindow( IxDispInfo.pScreen, FLM_RED, FLM_WHITE,
								"Suspending all indexes ....",
								NULL, &pMsgWin);

					f_mutexUnlock( IxDispInfo.hScreenMutex);

					if (RC_OK( pDb->transBegin( XFLM_UPDATE_TRANS)))
					{
						uiIndex = 0;
						for( ;;)
						{
							if( RC_BAD( pDb->indexGetNext( &uiIndex)))
							{
								break;
							}
							if (RC_BAD( pDb->indexSuspend( uiIndex)))
							{
								break;
							}
						}
						if (RC_BAD( pDb->transCommit()))
						{
							(void)pDb->transAbort();
						}
					}

					if( pMsgWin)
					{
						f_mutexLock( IxDispInfo.hScreenMutex);
						FTXWinFree( &pMsgWin);
						f_mutexUnlock( IxDispInfo.hScreenMutex);
					}
					goto Update_Screen;
				}

				case 'R':
				case FKB_ALT_R:
				{
					f_mutexLock( IxDispInfo.hScreenMutex);
					FTXMessageWindow( IxDispInfo.pScreen, FLM_RED, FLM_WHITE,
						"Resuming all indexes                                ",
						NULL,
						&pMsgWin);
					f_mutexUnlock( IxDispInfo.hScreenMutex);

					if (RC_OK( pDb->transBegin( XFLM_UPDATE_TRANS)))
					{
						uiIndex = 0;
						for( ;;)
						{
							if( RC_BAD( pDb->indexGetNext( &uiIndex)))
							{
								break;
							}

							if (RC_BAD( pDb->indexResume( uiIndex)))
							{
								break;
							}
						}
						if (RC_BAD( pDb->transCommit()))
						{
							(void)pDb->transAbort();
							break;
						}
					}
					if( pMsgWin)
					{
						f_mutexLock( IxDispInfo.hScreenMutex);
						FTXWinFree( &pMsgWin);
						f_mutexUnlock( IxDispInfo.hScreenMutex);
					}
					goto Update_Screen;
				}

				case 'T':
				case 't':
				{
					IxDispInfo.bShowTime = !IxDispInfo.bShowTime;
					goto Update_Screen;
				}

				case '?':
				{
					FTX_WINDOW *		pHelpWin = NULL;
					FTX_WINDOW *		pHelpTitle = NULL;
					F_DynamicList *	pHelpList = NULL;
					FLMUINT				uiItem = 0;
					char					szTmpBuf [100];

					f_mutexLock( IxDispInfo.hScreenMutex);
					bScreenLocked = TRUE;

					if( (pHelpList = f_new F_DynamicList) == NULL)
					{
						goto Help_Exit;
					}

					if( RC_BAD( FTXWinInit( IxDispInfo.pScreen, uiScreenCols,
						1, &pHelpTitle)))
					{
						goto Help_Exit;
					}

					FTXWinSetBackFore( pHelpTitle, FLM_RED, FLM_WHITE);
					FTXWinClear( pHelpTitle);
					FTXWinSetCursorType( pHelpTitle, FLM_CURSOR_INVISIBLE);
					FTXWinSetScroll( pHelpTitle, FALSE);
					FTXWinSetLineWrap( pHelpTitle, FALSE);
					FTXWinPrintf( pHelpTitle, "FLAIM Index Manager - Help");
					FTXWinOpen( pHelpTitle);

					if( RC_BAD( FTXWinInit( IxDispInfo.pScreen, uiScreenCols,
						uiScreenRows - 1, &pHelpWin)))
					{
						goto Help_Exit;
					}
					FTXWinDrawBorder( pHelpWin);
					FTXWinOpen( pHelpWin);
					pHelpList->setup( pHelpWin);

					f_sprintf( szTmpBuf, "R, ALT_R  Resume all indexes");
					pHelpList->update( ++uiItem, NULL, szTmpBuf, sizeof( szTmpBuf));

					f_sprintf( szTmpBuf, "S, ALT_S  Suspend all indexes");
					pHelpList->update( ++uiItem, NULL, szTmpBuf, sizeof( szTmpBuf));

					f_sprintf( szTmpBuf, "o, O      Toggle display of on-line indexes");
					pHelpList->update( ++uiItem, NULL, szTmpBuf, sizeof( szTmpBuf));

					f_sprintf( szTmpBuf, "+, r      Resume selected index with auto on-line option");
					pHelpList->update( ++uiItem, NULL, szTmpBuf, sizeof( szTmpBuf));

					f_sprintf( szTmpBuf, "s         Suspend selected index");
					pHelpList->update( ++uiItem, NULL, szTmpBuf, sizeof( szTmpBuf));

					pHelpList->refresh();
					pHelpWin = pHelpList->getListWin();

					f_mutexUnlock( IxDispInfo.hScreenMutex);
					bScreenLocked = FALSE;

					while( !gv_bShutdown)
					{
						f_mutexLock( IxDispInfo.hScreenMutex);
						bScreenLocked = TRUE;

						if( RC_OK( FTXWinTestKB( pHelpWin)))
						{
							FLMUINT		uiTmpChar;
							
							FTXWinInputChar( pHelpWin, &uiTmpChar);
							if( uiTmpChar == FKB_ESCAPE)
							{
								break;
							}
							pHelpList->defaultKeyAction( uiTmpChar);
						}

						f_mutexUnlock( IxDispInfo.hScreenMutex);
						bScreenLocked = FALSE;
						f_sleep( 10);
					}

Help_Exit:
					if( !bScreenLocked)
					{
						f_mutexLock( IxDispInfo.hScreenMutex);
						bScreenLocked = TRUE;
					}

					if( pHelpList)
					{
						pHelpList->Release();
					}

					if( pHelpTitle)
					{
						FTXWinFree( &pHelpTitle);
					}

					f_mutexUnlock( IxDispInfo.hScreenMutex);
					bScreenLocked = FALSE;
					break;
				}

				case FKB_ESCAPE:
				{
					goto Exit;
				}

				default:
				{
					f_mutexLock( IxDispInfo.hScreenMutex);
					pList->defaultKeyAction( uiChar);
					f_mutexUnlock( IxDispInfo.hScreenMutex);
					break;
				}
			}
			f_mutexLock( IxDispInfo.hScreenMutex);
			pList->refresh();
			f_mutexUnlock( IxDispInfo.hScreenMutex);
		}

		uiIterations++;

		if( pThread->getShutdownFlag())
		{
			break;
		}

		f_sleep( 1);
	}

Exit:

	if( pList)
	{
		pList->Release();
	}

	if (bRegisteredForEvent)
	{
		pDbSystem->deregisterForEvent( XFLM_EVENT_UPDATES, &event);
	}

	if( IxDispInfo.pScreen)
	{
		FTXScreenFree( &IxDispInfo.pScreen);
	}

	if( IxDispInfo.hScreenMutex != F_MUTEX_NULL)
	{
		f_mutexDestroy( &IxDispInfo.hScreenMutex);
	}
	
	if( pDb != NULL)
	{
		pDb->Release();
	}
	
	if( pDbSystem)
	{
		pDbSystem->Release();
	}

	return( rc);
}