/*
** Copyright (C) 1999 - 2002 Albert L. Faber
**  
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
** 
** This program 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 General Public License for more details.
** 
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software 
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/

#include "StdAfx.h"
#include "Config.h"
#include "Util.h"
#include "FileExistWarning.h"
#include <limits.h>
#include "ID3Lib/Zlib/include/zlib.h"
#include "FileVersion.h"

CLanguage		g_language;


/*
typedef union _ULARGE_INTEGER_WIN
{
   struct
   {
      DWORD LowPart;
      DWORD HighPart;
   }; DWORDLONG QuadPart;
} ULARGE_INTEGER_WIN;
*/

typedef BOOL (PASCAL *GFDPEX )(LPCTSTR,PULARGE_INTEGER,PULARGE_INTEGER,PULARGE_INTEGER);


// Local variables
static GFDPEX		GetDiskFreeSpaceOSR2=NULL;
static	HINSTANCE	gs_hDLLKernel=NULL;
static	BOOL		gs_bDetermineOSVersion=FALSE;
static	BOOL		gs_bNT=FALSE;

BOOL IsWindowsNTOS()
{
	return gs_bNT;
}

// return the amount of free disk space in KB!
DOUBLE GetMyFreeDiskSpace(CString& strPath)
{
	CString strRootDir;

	// Check input parameter
	if (strPath.IsEmpty())
	{
		ASSERT(FALSE);
		return 0;
	}

	// Copy driverletter, colon and back slash
	strRootDir=strPath.Left(3);

	DOUBLE dFreeDiskSpace=0.0;

	// Is this NT or OSR2, then call extented free disk space routine
	if ( NULL != GetDiskFreeSpaceOSR2 )
	{
		ULARGE_INTEGER	FreeBytes; 
		ULARGE_INTEGER	TotalNumberOfBytes;
		ULARGE_INTEGER	TotalNumberOfFreeBytes;

		// Make call to kernel 32 dll
		BOOL bReturn = GetDiskFreeSpaceOSR2(	strRootDir,
												&FreeBytes,
												&TotalNumberOfBytes,
												&TotalNumberOfFreeBytes );

		// If result is OK, then calculate result
		if (bReturn)
		{
			dFreeDiskSpace=(DOUBLE)FreeBytes.LowPart;
			dFreeDiskSpace+=((DOUBLE)FreeBytes.HighPart)*ULONG_MAX;
		}
	}
	else
	{
		// Standard Windows 95
 		DWORD dwSectorsPerCluster; 
		DWORD dwBytesPerSector; 
		DWORD dwNumberOfFreeClusters; 
		DWORD dwTotalNumberOfClusters;

		// Try the good old GetDiskFreeSpace
		GetDiskFreeSpace(strRootDir,&dwSectorsPerCluster,&dwBytesPerSector,&dwNumberOfFreeClusters,&dwTotalNumberOfClusters);
 
		// Calculate free disk space
		dFreeDiskSpace=(DOUBLE)dwNumberOfFreeClusters*(DOUBLE)dwBytesPerSector*(DOUBLE)dwSectorsPerCluster;

	// Get the free disc space as you already do.
	}
	return dFreeDiskSpace;
}


// Local prototypes
static BOOL DetermineOSVersion(void);



void InitUtil(void)
{
	DetermineOSVersion();
}

static BOOL DetermineOSVersion(void)
{
	if (!gs_bDetermineOSVersion)
	{
		OSVERSIONINFO osVersionInfo;

		// Set structure size filed of osVersionInfo
		osVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);

		// Get the actual Version
		GetVersionEx(&osVersionInfo);

		// Check if is OSR2
		if (	osVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS &&
				( osVersionInfo.dwBuildNumber & 0xFFFF) > 1000)
		{
			gs_bDetermineOSVersion= TRUE;
		}

		// Always true for Windows NT
		if (osVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT)
		{
			gs_bNT=TRUE;
			gs_bDetermineOSVersion= TRUE;
		}


		if (gs_bDetermineOSVersion)
		{
			gs_hDLLKernel = LoadLibrary( _T( "kernel32.dll" ) );
			if ( gs_hDLLKernel == NULL)
			{
				gs_bDetermineOSVersion= TRUE;
			}
			else
			{
				GetDiskFreeSpaceOSR2 = (GFDPEX)GetProcAddress( gs_hDLLKernel, "GetDiskFreeSpaceEx" );

				if ( NULL == GetDiskFreeSpaceOSR2 )
				{
					gs_bDetermineOSVersion= TRUE;
					FreeLibrary( gs_hDLLKernel );
				}
			}
		}
	}
	return gs_bDetermineOSVersion;
}

BOOL CheckNoFileOverwrite( CWnd* pWnd, CString strFileName, BOOL bAsk, BOOL& bYesToAll, BOOL& bNoToAll )
{
	BOOL bFileExist = FALSE;
	BOOL bOverwriteFile = FALSE;

	FILE* fp= _tfopen( strFileName, _T( "r" ) );

	// check if the file does exist
	if ( NULL != fp )
	{
		bFileExist = TRUE;
		fclose( fp );
	}

	if ( ( g_config.GetOverwriteExisting() == 1 ) || 
		 ( TRUE == bYesToAll ) )
	{
		return FALSE;
	}

	if ( bFileExist )
	{
		// pop up the overwrite dialog message?
		if ( ( TRUE == bAsk ) && ( bNoToAll == FALSE ) )
		{
			CFileExistWarning dlg;
			dlg.SetFileName( strFileName );

			if ( IDOK == dlg.DoModal() )
			{
				// Did the user request to overwrite all the files?
				bYesToAll = dlg.GetYesToAll();
				return FALSE;
			}
			else
			{
				bNoToAll = dlg.GetNoToAll();
				return TRUE;
			}
		}
		else
		{
			return TRUE;
		}
	}
	return FALSE;
}

BOOL LoadDLL(	const CString&	strDllName,
				const CString&	strPath,
				HINSTANCE&		hDll,
				BOOL			bShowWarning,
				BOOL			bUnicodeDLL )
{		
	BOOL bReturn = TRUE;
	CString strFullPathName;

	hDll = NULL;

	strFullPathName = g_config.GetAppPath() + _T( "\\" ) + strDllName;

	hDll = LoadLibrary( strFullPathName );

	CString strError = GetLastErrorString();


	if ( NULL == hDll )
	{
		strFullPathName = g_config.GetAppPath() + strPath + _T( "\\" ) + strDllName;
		hDll = LoadLibrary( strFullPathName );
	}

	// make an exception for the DBUG environment
	if ( NULL == hDll )
	{
		// Load the correct resource depending on the BUILD settings
#if _DEBUG
#if _UNICODE
		if ( bUnicodeDLL )
		{
			strFullPathName = g_config.GetAppPath() + strPath + _T( "\\Debug_UNICODE\\" ) + strDllName;
		}
		else
#endif
		{
			strFullPathName = g_config.GetAppPath() + strPath + _T( "\\Debug\\" ) + strDllName;
		}
#else
#if _UNICODE
		if ( bUnicodeDLL )
		{
			strFullPathName = g_config.GetAppPath() + strPath + _T( "\\Release_UNICODE\\" ) + strDllName;
		}
		else
#endif
		{
			strFullPathName = g_config.GetAppPath() + strPath + _T( "\\Release\\" ) + strDllName;
		}
#endif
		hDll = LoadLibrary( strFullPathName );
	}

	if ( NULL == hDll )
	{
		if ( TRUE == bShowWarning )
		{
			CString strLang;
			CString strMsg;

			strLang = g_language.GetString( IDS_LOADLIBRARY_FAILED );

			if ( strLang.IsEmpty() )
			{
				strMsg.Format( _T( "Could not load encoder: %s\nMake sure that you start CDex.exe where the DLLs are located\nIf you have created a short-cut, make sure the working directory is set correctly" ),
								strDllName );
			}
			else
			{
				strMsg.Format( strLang, strDllName );
			}

			AfxMessageBox( strMsg );
		}

		bReturn = FALSE;
	}

	return bReturn;
}

INT QueryModuleDebugLevel( const CString& strModule )
{
	int nReturn = 0;

	// Get the debug level for the specified module
	// from the CDex.ini file in the Debug section
	nReturn = ::GetPrivateProfileInt(	_T( "Debug" ),
										strModule,
										0,
										GetCDexAppPath() + _T( "\\CDex.ini" ) );

	return nReturn;

}

CString GetCDexAppPath()
{
	TCHAR  pszAppPath[ MAX_PATH + 1 ];
	TCHAR* pszSearch = NULL;

	memset( pszAppPath, 0, sizeof( pszAppPath ) );

	GetModuleFileName( NULL, pszAppPath, sizeof( pszAppPath ) );

	// find last \ character
	pszSearch = _tcsrchr( pszAppPath, _T( '\\' ) );

	if ( pszSearch )
	{
		// strip everything after the last \ char, \ char including 
		pszSearch[ 0 ] = '\0';
	}

	// Check if this running from a debug environment
#ifdef _UNICODE
	if (_tcsicmp(&pszSearch[ -14], _T( "\\DEBUG_UNICODE"  ) ) == 0 )
	{
		pszSearch[ -14 ] = '\0';
	}
	if (_tcsicmp(&pszSearch[ -16], _T( "\\RELEASE_UNICODE"  ) ) == 0 )
	{
		pszSearch[ -16 ] = '\0';
	}
		OutputDebugString( pszSearch );
#else
	if (_tcsicmp(&pszSearch[ -6], _T( "\\DEBUG"  ) ) == 0 )
	{
		pszSearch[ -6 ] = '\0';
	}
	if (_tcsicmp(&pszSearch[-8], _T( "\\RELEASE" ) ) == 0 )
	{
		pszSearch[ -8 ] = '\0';
	}
#endif
	return pszAppPath;
}

CDEX_ERR CalculateFileCrc32( const CString& strFileName, DWORD& dwCrc32 )
{
	CDEX_ERR	bReturn = CDEX_OK;
	const int	nBufSize = 1024;
	BYTE		buf[ nBufSize ];

	dwCrc32 = 0;

	FILE* pFile= _tfopen( strFileName, _T( "rb" ) );

	if ( NULL == pFile )
	{
		ASSERT( FALSE );
		bReturn = CDEX_FILEOPEN_ERROR;
	}
	else
	{
		bool bDone = false;
		while ( !bDone )
		{
			int nRead = fread( buf, 1, nBufSize, pFile );
			if ( nRead > 0 )
			{
				dwCrc32 = crc32( dwCrc32, buf, nRead );
			}
			if ( nRead < nBufSize )
			{
				bDone = true;
			}
		}

		fclose( pFile );
	}

	return bReturn;
}


BOOL UseFlatLookToolBar()
{
	BOOL bReturn = FALSE;

	// Get COMCTL32 version
	CFileVersion myVersion;

	TCHAR lpszModuleName[ MAX_PATH + 1 ] = { '\0',};

	// Get Comctl32.dll product version
	GetSystemDirectory( lpszModuleName,
						MAX_PATH );
	
	myVersion.Open( CString( lpszModuleName ) + _T( "\\COMCTL32.DLL" ) );

	CString strCompany( myVersion.GetCompanyName() );
	CString strVersion( myVersion.GetProductVersion() );
	CString strProductName( myVersion.GetProductName() );
	CString strFileVersion( myVersion.GetFileVersion() );


	float fVersion = 0.0f;
	_stscanf( strVersion, _T( "%f" ), & fVersion );

	BOOL	bDisableFlatLook=AfxGetApp()->GetProfileInt( _T( "Debug" ), _T( "DisableFlatLook" ),FALSE);

	if ( ( fVersion >= 4.70 ) && ( FALSE == bDisableFlatLook ) )
	{
		bReturn = TRUE;
	}

	return bReturn;
}

LPCSTR GetDosFileName( const CString& strPath )
{
	USES_CONVERSION;
	static TCHAR lpszPath[ MAX_PATH + 1 ];
	static CHAR lpszRet[ MAX_PATH + 1 ];
	static CHAR* lpszAscii;

	memset( lpszPath, 0, sizeof( lpszPath ) );

	// Get short directory name for output path
	GetShortPathName(	strPath,
						lpszPath,
						MAX_PATH ); 

	lpszAscii = W2A( lpszPath );
	strncpy( lpszRet, lpszAscii, MAX_PATH );

	return lpszRet;
}

BOOL AsciiOnly( const CString& strToTest )
{
#if _UNICODE
  for (int i=0; i<strToTest.GetLength();i++)
    {
		if ( strToTest.GetAt( i ) >= 0x80 )
        return false;
    }
#endif
  return true;
}
