// Jet3d - JMiniApp
// Filename:driver_list.cpp
/***************************************************************
Copyright (C) 2000 Novasoft Consulting

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Library General Public License for more details.

You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*****************************************************************/

/*****************************************************************************/
/*                            COMMON VERSION                                 */
/*****************************************************************************/

#include "jmini_app.h"

/*****************************************************************************/
/*                             PROCESSING FUNCTIONS                          */
/*****************************************************************************/ 
/*----------------------------------------------------------------------------
  Name:		GetModes(FuncResult *funcResult, jeDriver *driver, int ai_filter)
  Purpose:
  Notes:      

  1.  
----------------------------------------------------------------------------*/
ModeInfo*		
DriverList::GetModes(FuncResult *funcResult, jeDriver *driver, int ai_filter)
{
 ModeInfo		*modeInfo;
 ModeInfo		*tempModeInfo;
 jeDriver_Mode	*mode;
 const char		*lc_modeName;
 long			ll_width, ll_height;
 bool			lb_valid;

 // Initialize.
 funcResult->SetUndef();	
 modeInfo = tempModeInfo = NULL;



 // process all modes
 mode = jeDriver_GetNextMode(driver, NULL);
 while(mode)
 {
  // get mode name and dimensions
  jeDriver_ModeGetName(mode, &lc_modeName);
  jeDriver_ModeGetWidthHeight(mode, &ll_width, &ll_height);

  // See if this mode is ok.
  lb_valid = true;

  if((ai_filter & DRVLIST_WINDOW))
   if((ll_width != -1 ) && (ll_height != -1))
    lb_valid = false;

  
  if((ai_filter & DRVLIST_FULLSCREEN))
   if((ll_width == -1 ) && (ll_height == -1))
    lb_valid = false;

  // But you can override the filter, if you want?
  if(ai_filter & DRVLIST_ALL)
   lb_valid = true;
 


  // If this is a valid mode, add it to our list.
  if(lb_valid)
  {
   // We are interested in this driver so store info.
   // Allocate a new mode info.
   tempModeInfo = new ModeInfo();
  
   tempModeInfo->SetInitialized(); // Now in use.

   // Store the mode data.
   tempModeInfo->m_pMode = mode;
   strcpy(tempModeInfo->ic_modeName, lc_modeName);

   // Move to next element.
   tempModeInfo->nextMode = modeInfo;
   modeInfo = tempModeInfo;
  }


  // Get the next mode.
  mode = jeDriver_GetNextMode(driver, mode);
 }



 // Ok.
 funcResult->SetOk();


 // If no modes were found we will return null.
 return modeInfo;
}

/*----------------------------------------------------------------------------
  Name:		FindCurrentDriver(FuncResult *funcResult)
  Purpose:
  Notes:      

  1.  
----------------------------------------------------------------------------*/
DriverInfo*    
DriverList::FindCurrentDriver(FuncResult *funcResult)
{
 DriverInfo	*tempDrvInfo;
 bool		lb_found;

 // Init,
 funcResult->SetUndef();
 tempDrvInfo = m_pDrvListHead;
 lb_found = false;
 

 while(tempDrvInfo)
 {
  if(tempDrvInfo->ib_current)
  {
   lb_found = true;
   break;
  }

  tempDrvInfo = tempDrvInfo->nextDriver;
 }

 
 if(!lb_found)
 {
  tempDrvInfo = NULL; // Return NULL if not found.
  funcResult->SetError("Could not find the current driver", __LINE__, __FILE__);
  goto ReturnOut;
 }

 // Ok.
 funcResult->SetOk();

ReturnOut:
 return tempDrvInfo;
}

/*----------------------------------------------------------------------------
  Name:		FindCurrentMode(FuncResult *funcResult, DriverInfo &drvInfo)
  Purpose:
  Notes:      

  1.  
----------------------------------------------------------------------------*/
ModeInfo*
DriverList::FindCurrentMode(FuncResult *funcResult, DriverInfo &drvInfo)
{
 ModeInfo	*tempModeInfo;
 bool		lb_found;

 // Init,
 funcResult->SetUndef();
 tempModeInfo = drvInfo.imodeInfo;
 lb_found = false;	

 
 while(tempModeInfo)
 {
  if(tempModeInfo->ib_current)
  {
   lb_found = true;
   break;
  }

  tempModeInfo = tempModeInfo->nextMode;
 }

 
 if(!lb_found)
 {
  tempModeInfo = NULL; // Return NULL if not found.
  funcResult->SetError("Could not find the current mode for the current driver", __LINE__, __FILE__);
  goto ReturnOut;
 }

 // Ok.
 funcResult->SetOk();

ReturnOut:
 return tempModeInfo;
}

/*****************************************************************************/
/*									INTERFACE FUNCTIONS		      		     */
/*****************************************************************************/

DriverList::DriverList(void)
{
 m_pDrvListHead = NULL;
 ib_initialized = false;
}

DriverList::~DriverList(void)
{
 Release(); 
}

/*----------------------------------------------------------------------------
  Name:		Initialize(FuncResult *funcResult, int ai_filter)
  Purpose:	Build the driver (and mode) list.
  Notes:      

  1.  
----------------------------------------------------------------------------*/
void			
DriverList::Initialize(FuncResult *funcResult, int ai_filter)
{
 jeDriver_System	*driverSystem;
 jeDriver			*driver;
 bool				lb_valid;
 DriverInfo			*tempDrvInfo;
 const char			*lc_drvName;
 ModeInfo			*tempModeInfo;

 
 // Initialize.
 funcResult->SetUndef();
 tempDrvInfo = NULL;
 tempModeInfo = NULL;



 // get driver system
 driverSystem = jeEngine_GetDriverSystem(worldManager->m_pEngine);
 if(!driverSystem)
 {
  funcResult->SetError("Could not get a system driver", __LINE__, __FILE__);
  goto ReturnOut;
 }
 

 // process all drivers
 driver = jeDriver_SystemGetNextDriver(driverSystem, NULL);
 while(driver)
 {
  // Get the drivers name.
  jeDriver_GetName(driver, &lc_drvName);
	 
  
  // See if this driver is one we want.
  lb_valid = true;

  if((ai_filter & DRVLIST_SOFTWARE))
   if(strnicmp(lc_drvName, "Software", 8 ) != 0)
    lb_valid = false;

		 
  if((ai_filter & DRVLIST_HARDWARE))
   if(strnicmp(lc_drvName, "Software", 8 ) == 0)
    lb_valid = false;

		
  // But you can override the filter, if you want?
  if(ai_filter & DRVLIST_ALL)
   lb_valid = true;


  if(lb_valid)
  {
    // Get all of this drivers valid modes.
   tempModeInfo = GetModes(funcResult, driver, ai_filter);
   if(funcResult->GetFailed())
    goto ReturnOut;


   // Make sure we got at least one valid mode for this driver!
   if(tempModeInfo)
   {
    // We are now interested in this driver so store info.
    tempDrvInfo = new DriverInfo();
    if(!tempDrvInfo)
	{
     Release();
     funcResult->SetError(FUNCR_COULDNOTALLOCMEM, __LINE__, __FILE__);
	 goto ReturnOut;
	}
	   
	tempDrvInfo->SetInitialized(); // Now in use.
   
    // Store the actual driver.
	tempDrvInfo->m_pDriver = driver;

	// Store this drivers name.
    strcpy(tempDrvInfo->ic_driverName, lc_drvName); 
    
	// Store all modes for this driver.
	tempDrvInfo->imodeInfo = tempModeInfo; 


    // Move to next element.
    tempDrvInfo->nextDriver = m_pDrvListHead;
    m_pDrvListHead = tempDrvInfo;
   }
  }
  


  // get next driver
  driver = jeDriver_SystemGetNextDriver(driverSystem, driver);
 }

 
 // Ok.
 ib_initialized = true;
 funcResult->SetOk();

ReturnOut:
 // Any cleanup here.

 return;
}
  


/*----------------------------------------------------------------------------
  Name:		SelectDriver(FuncResult *funcResult, char *ac_drvName)
  Purpose:
  Notes:      

  1.  
----------------------------------------------------------------------------*/
void			
DriverList::SelectDriver(FuncResult *funcResult, char *ac_drvName)
{
 DriverInfo		*tempDrvInfo;
 bool			lb_found;

 // Check args.
 if(!ac_drvName)
 {
  funcResult->SetError(FUNCR_INVAILDARGS, __LINE__, __FILE__);
  goto ReturnOut;
 }

 // Init,
 funcResult->SetUndef();
 tempDrvInfo = NULL;
 lb_found = false;

 if(!ib_initialized)
 {
  funcResult->SetError(FUNCR_OBJECTNOTINITIALIZED, __LINE__, __FILE__);
  goto ReturnOut;
 } 

 if(!m_pDrvListHead)
 {
  funcResult->SetError(FUNCR_OBJECTNOTCREATED, "Could not set driver", __LINE__, __FILE__);
  goto ReturnOut;
 }

 tempDrvInfo = m_pDrvListHead;


 // Unselect any previous current driver.
 while(tempDrvInfo)
 {
  if(tempDrvInfo->ib_current)
  {
   tempDrvInfo->ib_current = false;
   break; // Should only ever be one current driver.
  }

  tempDrvInfo = tempDrvInfo->nextDriver;
 }


 // Then try and select the specified driver.
 tempDrvInfo = m_pDrvListHead;


 while(tempDrvInfo)
 {
  if(strcmp(tempDrvInfo->ic_driverName, ac_drvName) == 0)
  {
   tempDrvInfo->ib_current = false;
   lb_found = true;
   break; 
  }

  tempDrvInfo = tempDrvInfo->nextDriver;
 }


 if(!lb_found)
 {
  funcResult->SetError("Unknown driver specified", __LINE__, __FILE__);
  goto ReturnOut;
 }

 // Ok.
 funcResult->SetOk();


ReturnOut:
 return;
}

/*----------------------------------------------------------------------------
  Name:		SelectDefaultDriver(FuncResult *funcResult)
  Purpose:
  Notes:	The default driver is always the first driver.     

  1.  
----------------------------------------------------------------------------*/
void			
DriverList::SelectDefaultDriver(FuncResult *funcResult)
{
 DriverInfo		*tempDrvInfo;


 // Init,
 funcResult->SetUndef();
 tempDrvInfo = NULL;
 

 if(!ib_initialized)
 {
  funcResult->SetError(FUNCR_OBJECTNOTINITIALIZED, __LINE__, __FILE__);
  goto ReturnOut;
 } 

 if(!m_pDrvListHead)
 {
  funcResult->SetError(FUNCR_OBJECTNOTCREATED, "Could not select a default driver", __LINE__, __FILE__);
  goto ReturnOut;
 }

 tempDrvInfo = m_pDrvListHead;

 // Unselect any previous current driver.
 while(tempDrvInfo)
 {
  if(tempDrvInfo->ib_current)
  {
   tempDrvInfo->ib_current = false;
   break; // Should only ever be one current driver.
  }

  tempDrvInfo = tempDrvInfo->nextDriver;
 }
 
 

 // Ok.
 m_pDrvListHead->ib_current = true; // Set the default driver.
 funcResult->SetOk();


ReturnOut:
 return;
}

/*----------------------------------------------------------------------------
  Name:		GetCurrentDriverName(FuncResult *funcResult)
  Purpose:
  Notes:      

  1.  
----------------------------------------------------------------------------*/
char*
DriverList::GetCurrentDriverName(FuncResult *funcResult)
{
 DriverInfo		*tempDrvInfo;
 bool			lb_found;
 char			*lc_drvName;

 // Init,
 funcResult->SetUndef();
 tempDrvInfo = NULL;
 lb_found = false;
 lc_drvName = NULL;


 if(!ib_initialized)
 {
  funcResult->SetError(FUNCR_OBJECTNOTINITIALIZED, __LINE__, __FILE__);
  goto ReturnOut;
 }


 tempDrvInfo = FindCurrentDriver(funcResult);
 if(funcResult->GetFailed())
  goto ReturnOut;

 lc_drvName = tempDrvInfo->ic_driverName;

 // Ok.
 funcResult->SetOk();

ReturnOut:
 return lc_drvName; // Return NULL if not found.
}

/*----------------------------------------------------------------------------
  Name:		GetCurrentModeName(FuncResult *funcResult)
  Purpose:
  Notes:      

  1.  
----------------------------------------------------------------------------*/
char*
DriverList::GetCurrentModeName(FuncResult *funcResult)
{
 DriverInfo		*tempDrvInfo;
 ModeInfo		*tempModeInfo;
 bool			lb_found;
 char			*lc_modeName;			
 

 // Init,
 funcResult->SetUndef();
 tempDrvInfo = NULL;
 tempModeInfo = NULL;
 lb_found = false;
 lc_modeName = NULL;


 if(!ib_initialized)
 {
  funcResult->SetError(FUNCR_OBJECTNOTINITIALIZED, __LINE__, __FILE__);
  goto ReturnOut;
 }

 tempDrvInfo = FindCurrentDriver(funcResult);
 if(funcResult->GetFailed())
  goto ReturnOut;

 // Now we've found the current driver we can find the current mode.
 tempModeInfo = FindCurrentMode(funcResult, *tempDrvInfo);
 if(funcResult->GetFailed())
  goto ReturnOut;



 lc_modeName = tempModeInfo->ic_modeName;


 // Ok.
 funcResult->SetOk();

ReturnOut:
 return lc_modeName; // Return NULL if not found.
}

/*----------------------------------------------------------------------------
  Name:		GetCurrentDriver(FuncResult *funcResult)
  Purpose:
  Notes:      

  1.  
----------------------------------------------------------------------------*/
jeDriver*
DriverList::GetCurrentDriver(FuncResult *funcResult)
{
 DriverInfo		*tempDrvInfo;
 bool			lb_found;
 jeDriver		*driver;


 // Init,
 funcResult->SetUndef();
 tempDrvInfo = NULL;
 lb_found = false;
 driver = NULL;


 if(!ib_initialized)
 {
  funcResult->SetError(FUNCR_OBJECTNOTINITIALIZED, __LINE__, __FILE__);
  goto ReturnOut;
 }


 tempDrvInfo = FindCurrentDriver(funcResult);
 if(funcResult->GetFailed())
  goto ReturnOut;


 driver = tempDrvInfo->m_pDriver;


 // Ok.
 funcResult->SetOk();
 


ReturnOut:
 return driver; // Return Null if no driver is current.
}

/*----------------------------------------------------------------------------
  Name:		GetCurrentMode(FuncResult *funcResult)
  Purpose:
  Notes:      

  1.  
----------------------------------------------------------------------------*/
jeDriver_Mode*
DriverList::GetCurrentMode(FuncResult *funcResult)
{
 DriverInfo		*tempDrvInfo;
 ModeInfo		*tempModeInfo;
 bool			lb_found;
 jeDriver_Mode	*mode;


 // Init,
 funcResult->SetUndef();
 tempDrvInfo = NULL;
 tempModeInfo = NULL;
 lb_found = false;
 mode = NULL;


 if(!ib_initialized)
 {
  funcResult->SetError(FUNCR_OBJECTNOTINITIALIZED, __LINE__, __FILE__);
  goto ReturnOut;
 }

 tempDrvInfo = FindCurrentDriver(funcResult);
 if(funcResult->GetFailed())
  goto ReturnOut;

 // Now we've found the current driver we can find the current mode.
 tempModeInfo = FindCurrentMode(funcResult, *tempDrvInfo);
 if(funcResult->GetFailed())
  goto ReturnOut;
 

   
 mode = tempModeInfo->m_pMode;


 // Ok.
 funcResult->SetOk();
 


ReturnOut:
 return mode; // Return Null if no mode is current.
}

/*----------------------------------------------------------------------------
  Name:		Release(void)
  Purpose:
  Notes:	This func deletes from the head and moves forward through the list deleting nodes.    

  1.  
----------------------------------------------------------------------------*/
void
DriverList::Release(void)
{
 DriverInfo		*tempDrv;
 ModeInfo		*tempMode1, *tempMode2;
 
 // Initialize.
 tempDrv = NULL;
 tempMode1 = tempMode2 = NULL;

 tempDrv = m_pDrvListHead;
 

 while(m_pDrvListHead)
 {
  
  tempMode1 = m_pDrvListHead->imodeInfo;
  
  // Delete all the modes for this driver.
  while(tempMode1)
  {
   tempMode2 = tempMode1->nextMode;
   delete tempMode1;
   tempMode1 = tempMode2;
  }

  // Then delete the driver.
  tempDrv = m_pDrvListHead->nextDriver;
  delete m_pDrvListHead;
  
  m_pDrvListHead = tempDrv;
 }
}


