/*
 =======================================================================================
  Name        :Vss5_Fct.cpp
 
  Author      :Vincent lhullier             Date :15/04/97
 
  Description : implement single selection
 =======================================================================================
  Modification -> Author :                  Date :
  Description :
 =======================================================================================
 */

#include "stdafx.h"
#include <io.h>
#include <sys\stat.h>
#include "vss5_fct.h"
#include "inidata.h"
#include "DlgLogin.h"

#include "ssmyauto.h"
#include "ssauterr.h"
#include "error.h"

/*
 =======================================================================================
  CONSTANTS
 =======================================================================================
 */
#define C_szRootProject	"$/"

/*
 =======================================================================================
  GLOBALS
 =======================================================================================
 */
IVSSDatabase	OLE_g_oDatabase(NULL, FALSE);

char g_cNbUsers;
char g_a_szUserName[10][20];

HWND g_hProjectWindow;

static char g_szSpecialFile[ MAX_PATH ] = {""};

/*
 =======================================================================================
  NOT VSS SPECIFIC FUNCTIONS
 =======================================================================================
 */

void fn_vTransformSpec( char *_szSpec )
{
	char *p_szAntiSlash = _szSpec;
	while( (p_szAntiSlash = strchr( p_szAntiSlash, '\\')) != NULL)
		*p_szAntiSlash = '/';

	if ( strcmp( C_szRootProject, "$") == 0)
		if ( (*_szSpec=='$') && (*(_szSpec+1)=='/') )
			memmove( _szSpec + 1, _szSpec + 2, strlen( _szSpec + 1 ) );
}

/*
 =======================================================================================
  LOW LEVEL FUNCTIONS
 =======================================================================================
 */

/*----------------------------------------------------------------------------------------------------*/
BOOL OLE_fn_bGetItemContent( IVSSItem *_p_oItem, IVSSItems *_p_oContent )
{
	LPDISPATCH p_oDisp;

	p_oDisp = _p_oItem->GetItems( FALSE );
	_p_oContent->AttachDispatch( p_oDisp );
	return TRUE;
}

/*----------------------------------------------------------------------------------------------------*/
BOOL OLE_fn_bGetContentItem( IVSSItems *_p_oContent, int iItem, IVSSItem *_p_oItem )
{
	LPDISPATCH	p_oDisp;
	VARIANT		vItem;
	
	if ( (iItem < 1) || (iItem > _p_oContent->GetCount() ) )
		return FALSE;

	vItem.vt = VT_I2;
	vItem.iVal = iItem;

	p_oDisp = _p_oContent->GetItem( vItem );
	_p_oItem->AttachDispatch( p_oDisp );
	return TRUE;
}

/*----------------------------------------------------------------------------------------------------*/
BOOL OLE_fn_bGetLocalItem( char *_szSpec, IVSSItem *_p_oItem, IVSSItem *_p_oLocalItem, char _cType )
{
	IVSSItems	oContent;
	long		lCount;
	int			iItem;
	long		lType;
	CString		oStr;

	OLE_fn_bGetItemContent( _p_oItem, &oContent );
	lCount = oContent.GetCount();
	
	for ( iItem = 1; iItem <= lCount ; iItem ++ )
	{
		OLE_fn_bGetContentItem( &oContent, iItem, _p_oLocalItem);
		lType = _p_oLocalItem->GetType();

		if  (
				((lType == VSSITEM_PROJECT) && (_cType & C_cSearchForProject)) ||
				((lType == VSSITEM_FILE) && (_cType & C_cSearchForFile))
			)
		{
			oStr = _p_oLocalItem->GetName();
			if ( stricmp( (char *) LPCTSTR(oStr), _szSpec ) == 0)
				return TRUE;
		}
		_p_oLocalItem->ReleaseDispatch();
	}
	return FALSE;
}

/*----------------------------------------------------------------------------------------------------*/
BOOL OLE_fn_bDoesLocalItemExist( char *_szSpec, IVSSItem *_p_oItem, char _cType )
{
	IVSSItem oLocalItem;
	return (OLE_fn_bGetLocalItem( _szSpec, _p_oItem, &oLocalItem, _cType ));
}

/*----------------------------------------------------------------------------------------------------*/
BOOL OLE_fn_bGetLocalFile( char *_szFileSpec, IVSSItem *_p_oItem, IVSSItem *_p_oLocalItem )
{
	return (OLE_fn_bGetLocalItem( _szFileSpec, _p_oItem, _p_oLocalItem, C_cSearchForFile ));
}

/*----------------------------------------------------------------------------------------------------*/
BOOL OLE_fn_bGetLocalProject( char *_szProjectSpec, IVSSItem *_p_oItem, IVSSItem *_p_oLocalItem )
{
	return (OLE_fn_bGetLocalItem( _szProjectSpec, _p_oItem, _p_oLocalItem, C_cSearchForProject ));
}

/*----------------------------------------------------------------------------------------------------*/
BOOL OLE_fn_bDoesLocalFileExist( char *_szFileSpec, IVSSItem *_p_oItem )
{
	return (OLE_fn_bDoesLocalItemExist( _szFileSpec, _p_oItem, C_cSearchForFile ));
}

/*----------------------------------------------------------------------------------------------------*/
BOOL OLE_fn_bDoesLocalProjectExist( char *_szProjectSpec, IVSSItem *_p_oItem )
{
	return (OLE_fn_bDoesLocalItemExist( _szProjectSpec, _p_oItem, C_cSearchForProject ));
}

/*----------------------------------------------------------------------------------------------------*/
BOOL OLE_fn_bGetRootProject (IVSSItem *_p_oItem )
{
	LPDISPATCH p_oDisp;
	p_oDisp = OLE_g_oDatabase.GetVSSItem( C_szRootProject, FALSE );
	_p_oItem->AttachDispatch( p_oDisp );
	return TRUE;
}

/*----------------------------------------------------------------------------------------------------*/
BOOL OLE_fn_bGetExistantItem( char *_szSpec, IVSSItem *_p_oItem )
{
	LPDISPATCH p_oDisp;

	if ( strlen(_szSpec) > 129 )
	{
		char		*szLocal[ 20 ];
		char		cLocal = 0;
		IVSSItem	oItem;
		BOOL		bResult;

		while (strlen( _szSpec ) > 129 )
		{
			szLocal[cLocal] = strrchr( _szSpec, '\\' );
			*szLocal[cLocal] =0;
			cLocal++;
		}

		bResult = OLE_fn_bGetExistantItem( _szSpec, &oItem );
		if (bResult)
		{
			for ( ; cLocal > 0; cLocal--)
			{
				if (!OLE_fn_bGetLocalItem( szLocal[ cLocal - 1 ] + 1, &oItem, _p_oItem, C_cSearchForAll) )
				{
					bResult = FALSE;
					break;
				}
				*szLocal[ cLocal - 1 ] = '\\';
				oItem = *_p_oItem;
			}
		}

		for ( ; cLocal > 0; cLocal--)
			*szLocal[ cLocal - 1 ] = '\\';
	
		return bResult;
	}

	TRY
		p_oDisp = OLE_g_oDatabase.GetVSSItem( _szSpec, FALSE );
	CATCH_ALL(e)
		Error_fn_vSetFmt( Error_eCantAccessExistantItem, "Unable to access existant item called\r\n%s", _szSpec );
		return FALSE;
	END_CATCH_ALL
	_p_oItem->AttachDispatch( p_oDisp );
	return TRUE;
}

/*
 ----------------------------------------------------------------------------------------
  Description   : look if a project exist, if no return in _p_oVssItem the last parent 
				project that does exist. If project exist it is returned in _p_oVssItem
				if _p_oVssItem is NULL it is not used
  _szProjSpec          -> project full name
  _p_oVssItem          -> last existant parent or 
  Returns (BOOL) TRUE if success
 ----------------------------------------------------------------------------------------
 */
BOOL OLE_fn_bDoesProjectExist( char *_szProjSpec, IVSSItem *_p_oVssItem )
{
	IVSSItem	oItem;
	IVSSItem	oLocalItem;
	char		*szLocalSpec;
	char		*szNext;
	BOOL		bEnd;

	if (_p_oVssItem == NULL)
		_p_oVssItem = &oItem;

	// transform spec to be sure of format
	fn_vTransformSpec( _szProjSpec );

	// get root project
	OLE_fn_bGetRootProject( _p_oVssItem );

	// look if it's a possible project
	if ( strncmp( _szProjSpec, C_szRootProject, strlen(C_szRootProject) ) )
	{
		_p_oVssItem->ReleaseDispatch();
		return FALSE;
	}

	// get first local project 
	szLocalSpec = _szProjSpec + strlen( C_szRootProject );

	if (*szLocalSpec == 0)
		return TRUE;

	while ( 1 )
	{
		// get next project
		szNext = strchr( szLocalSpec, '/' );
		// store if it's the last project
		bEnd = (szNext == NULL);
		if (!bEnd)
			*szNext = 0;

		// try to get local project in current project
		if (!OLE_fn_bGetLocalProject( szLocalSpec, _p_oVssItem, &oLocalItem ))
		{
			if(!bEnd)
				*szNext = '/';
			return FALSE;
		}

		*_p_oVssItem = oLocalItem;

		if (bEnd)
			break;
		// restore global project spec and go to next project
		*szNext = '/';
		szLocalSpec = szNext + 1;
	} 
	return TRUE;
}


/*
 ----------------------------------------------------------------------------------------
  Description   : change current project, if project doesn't exist create it
  _szProjSpec          -> name of project
  Returns (BOOL) TRUE if success
 ----------------------------------------------------------------------------------------
 */
BOOL OLE_fn_bCreateVssProject( char *_szProjSpec )
{
	IVSSItem	oItem;
	CString		oStr;
	char		*szLocal;
	char		*szNext;
	BOOL		bEnd;
	LPDISPATCH	p_oDispatch;
	IVSSItem	oTempItem;

	if (!OLE_fn_bDoesProjectExist( _szProjSpec, &oItem ))
	{
		// must add project
		oStr = oItem.GetSpec();

		szLocal = _szProjSpec + oStr.GetLength() + 1;
		
		while ( 1 )
		{
			// get next project
			szNext = strchr( szLocal, '/' );
			// store if it's the last project
			bEnd = (szNext == NULL);
			if (!bEnd)
				*szNext = 0;

			// try to get local project in current project
			TRY
				p_oDispatch = oItem.NewSubproject( szLocal, "Generated by MngData" );
			CATCH_ALL( e )
				char szError[1024];
				e->GetErrorMessage( szError, 1024 );
				Error_fn_vSetFmt( Error_eAccessDenied, "%s\r\n", szError );
				return FALSE;
			END_CATCH_ALL

			oItem.ReleaseDispatch();
			oItem.AttachDispatch( p_oDispatch );
		
			if (bEnd)
				break;
			// restore global project spec and go to next project
			*szNext = '/';
			szLocal = szNext + 1;
		} 
	}
	
	return TRUE;
}


/*
 ----------------------------------------------------------------------------------------
  Description   : add a file in vss database
  _szFileSpec         -> full vss filename including project
  _szLocalFile        -> local file name
  Returns (BOOL) TRUE if success
 ----------------------------------------------------------------------------------------
 */
BOOL OLE_fn_bAddFile( char *_szInProj, char *_szLocalFile )
{
	IVSSItem	oItem;
	char		szTempFile[ MAX_PATH ];
	char		*p_szLocalFile;
	BOOL		bTooLong;

	if (!OLE_fn_bCreateVssProject( _szInProj ) )
		return FALSE;

	if (!OLE_fn_bGetExistantItem( _szInProj, &oItem ) )
		return FALSE;

	/* check lenght of local file */
	bTooLong = strlen( _szLocalFile ) > 129;
	if (bTooLong)
	{
		p_szLocalFile = strrchr( _szLocalFile, '\\');
		if (p_szLocalFile == NULL)
			return FALSE;
		sprintf( szTempFile, "%s%s", g_stIniData.szTempPath, p_szLocalFile );
		p_szLocalFile = szTempFile;
		CopyFile( _szLocalFile, p_szLocalFile, FALSE );
	}
	else
		p_szLocalFile = _szLocalFile;

	TRY
		oItem.Add( p_szLocalFile, "File added by MngData5" , VSSFLAG_USERRONO);
	CATCH_ALL( e )
		char szError[1024];
		e->GetErrorMessage( szError, 1024 );
		Error_fn_vSetFmt( Error_eAccessDenied, "%s\r\n", szError );
		return FALSE;
	END_CATCH_ALL

	return TRUE;
}


/*
 ----------------------------------------------------------------------------------------
  Description   : checkout a file
  _szFileSpec         -> full name of file to checkout
  _szLocalFile        -> local name
  Returns (BOOL ) TRUE if success
 ----------------------------------------------------------------------------------------
 */
BOOL OLE_fn_bCheckoutFile( char *_szFileSpec, char *_szLocalFile, int iFlags )
{
	IVSSItem oItem;

	if (!OLE_fn_bGetExistantItem( _szFileSpec, &oItem ) )
		return FALSE;

	CString cstr = oItem . GetSpec();
	
	TRY
		oItem.Checkout( "Check-out by MngData5", _szLocalFile, iFlags);
	CATCH_ALL( e )
		char szError[1024];
		e->GetErrorMessage( szError, 1024 );
		Error_fn_vSetFmt( Error_eAccessDenied, "%s", szError );
		return FALSE;
	END_CATCH_ALL

	return TRUE;
}


/*
 ----------------------------------------------------------------------------------------
  Description   : undo checkout for given vss file
  _szFileSpec         -> full vss file spec
  _szLocalFile        ->
  Returns (BOOL )
 ----------------------------------------------------------------------------------------
 */
BOOL OLE_fn_bUndoCheckoutFile( char *_szFileSpec, char *_szLocalFile, int _iFlags )
{
	IVSSItem oItem;

	if (!OLE_fn_bGetExistantItem( _szFileSpec, &oItem ) )
		return FALSE;

	TRY
		oItem.UndoCheckout( _szLocalFile, _iFlags);
	CATCH_ALL( e )
		char szError[1024];
		e->GetErrorMessage( szError, 1024 );
		Error_fn_vSetFmt( Error_eAccessDenied, "%s\r\n", szError );
		return FALSE;
	END_CATCH_ALL

	return TRUE;
}

/*
 ----------------------------------------------------------------------------------------
  Description   : checkin a file
  _szFileSpec         -> full name of file to checkin
  _szLocalFile        -> local name (NULL is possible)
  Returns (BOOL ) TRUE if success
 ----------------------------------------------------------------------------------------
 */
BOOL OLE_fn_bCheckinFile( char *_szFileSpec, char *_szLocalFile, int iFlags )
{
	IVSSItem oItem;

	if (!OLE_fn_bGetExistantItem( _szFileSpec, &oItem ) )
		return FALSE;

	if (oItem.GetIsCheckedOut() == VSSFILE_NOTCHECKEDOUT)
		return FALSE;

	TRY
		oItem.Checkin( "Check-in by MngData5", _szLocalFile, iFlags);
	CATCH_ALL( e )
		char szError[1024];
		e->GetErrorMessage( szError, 1024 );
		Error_fn_vSetFmt( Error_eAccessDenied, "%s\r\n", szError );
		return FALSE;
	END_CATCH_ALL

	return TRUE;
}


/*
 ----------------------------------------------------------------------------------------
  Description   : get file
  _szSpec             -> full spec name of vss item
  _szLocalPath        -> local path where vss item must be obtain
  _iFlags             -> flags (recurse or not)
  Returns (BOOL )
 ----------------------------------------------------------------------------------------
 */
BOOL OLE_fn_bGetFile( char *_szSpec, char *_szLocalPath, int _iFlags, BOOL _bFile, BOOL *_bObtained )
{
	IVSSItem		oItem;
	char			*p_szLocalPath;
	BOOL			bTooLong;

	_iFlags |= VSSFLAG_FORCEDIRNO | VSSFLAG_REPREPLACE | VSSFLAG_USERRONO;

	bTooLong = strlen( _szLocalPath ) > 129;
	if (bTooLong)
	{
		if (*g_szSpecialFile  == 0)
			sprintf( g_szSpecialFile, "%s\\KillBill.txt", g_stIniData.szTempPath );
		p_szLocalPath = g_szSpecialFile;
	}
	else
		p_szLocalPath = _szLocalPath;
	

	if (!OLE_fn_bGetExistantItem( _szSpec, &oItem ) )
		return FALSE;

	if (_bFile)
	{
		if (_access( _szLocalPath, 0) == 0)
		{
			if (bTooLong)
				CopyFile( _szLocalPath, p_szLocalPath, FALSE );

			TRY
				*_bObtained = oItem.GetIsDifferent( p_szLocalPath );
			CATCH_ALL( e )
				char szError[1024];
				e->GetErrorMessage( szError, 1024 );
				AfxMessageBox( szError,  MB_ICONSTOP );
			END_CATCH_ALL
		}
		else
			*_bObtained = TRUE;
			
		if (!*_bObtained)
			return TRUE;
	}
	else
		*_bObtained = TRUE;

	COleVariant		oLocal( p_szLocalPath );
	VARIANT			vLocal = oLocal.Detach();

	TRY
		oItem.Get( &vLocal.bstrVal , _iFlags );
	CATCH_ALL( e )
		char szError[1024];
		char *p_szError;

		p_szError = szError + sprintf( szError, "Error when trying to obtain\n  %s vss file to\n  %s file :\n", _szSpec, _szLocalPath );
		e->GetErrorMessage( p_szError, 1024 );
		
		AfxMessageBox( szError,  MB_ICONSTOP );
		return FALSE;
	END_CATCH_ALL

	if (bTooLong)
	{
		if (_access( _szLocalPath, 2) != 0)
			_chmod( _szLocalPath, _S_IWRITE );
		CopyFile( p_szLocalPath, _szLocalPath, FALSE );
	}

	return TRUE;
}

/*
 ----------------------------------------------------------------------------------------
  Description   : update a Vss File with a local file
  _szSpec             -> full spec name of vss item
  _szLocalPath        -> full name of local file
  _iFlags             -> flags
  Returns (BOOL ) TRUE if success
 ----------------------------------------------------------------------------------------
 */
char OLE_fn_cUpdateFile( char *_szSpec, char *_szLocalName )
{
	IVSSItem		oItem;
	char			*p_szLocalPath;
	BOOL			bTooLong;
	BOOL			bIsDifferent;
	int				iFlags;

	/* check local file */
	if (_access( _szLocalName, 0) != 0)
	{
		Error_fn_vSetFmt(Error_eLocalFileNotFound, "Local file %s doesn't exist", _szLocalName );
		return C_Vss_cUpdateError;
	}

	iFlags = VSSFLAG_USERRONO;

	if (!OLE_fn_bGetExistantItem( _szSpec, &oItem ) )
	{
		/* vss file doesn't exist, add it */
		char *szEndProjName;

		szEndProjName = strrchr( _szSpec, '\\' );
		if (szEndProjName == NULL)
			return C_Vss_cUpdateError;
		*szEndProjName = 0;
		
		bIsDifferent = OLE_fn_bAddFile( _szSpec, _szLocalName );
		*szEndProjName = '\\';
		return (bIsDifferent ? C_Vss_cUpdateAdd : C_Vss_cUpdateError);
	}

	/* check lenght of local file */
	bTooLong = strlen( _szLocalName ) > 129;
	if (bTooLong)
	{
		if (*g_szSpecialFile  == 0)
			sprintf( g_szSpecialFile, "%s\\KillBill.txt", g_stIniData.szTempPath );
		p_szLocalPath = g_szSpecialFile;
		CopyFile( _szLocalName, p_szLocalPath, FALSE );
	}
	else
		p_szLocalPath = _szLocalName;

	TRY
		bIsDifferent = oItem.GetIsDifferent( p_szLocalPath );
	CATCH_ALL( e )
		char szError[1024];
		e->GetErrorMessage( szError, 1024 );
		AfxMessageBox( szError,  MB_ICONSTOP );
	END_CATCH_ALL
			
	if (!bIsDifferent)
		return C_Vss_cUpdateNothing;
	

	TRY
		oItem.Checkout( "Check-out by MngData5", p_szLocalPath, VSSFLAG_GETNO );
		oItem.Checkin( "Check-in by MngData5", p_szLocalPath, VSSFLAG_USERRONO);
	CATCH_ALL( e )
		char szError[1024];
		e->GetErrorMessage( szError, 1024 );
		Error_fn_vSetFmt( Error_eAccessDenied, "%s", szError );
		return C_Vss_cUpdateError;
	END_CATCH_ALL

	if (bTooLong)
	{
		if (_access( _szLocalName, 2) != 0)
			_chmod( _szLocalName, _S_IWRITE );
		CopyFile( p_szLocalPath, _szLocalName, FALSE );
	}

	return C_Vss_cUpdateModify;
}

/*
 ----------------------------------------------------------------------------------------
  Description   : destroy a file in vss database
  _szSpec				-> full vss filename including project
  Returns (BOOL) TRUE if success
 ----------------------------------------------------------------------------------------
 */
BOOL OLE_fn_bDestroyFile( char *_szSpec )
{
	IVSSItem	oItem;

	if (!OLE_fn_bGetExistantItem( _szSpec, &oItem ) )
		return TRUE;

	TRY
		oItem.Destroy();
	CATCH_ALL( e )
		char szError[1024];
		char *p_szError;

		p_szError = szError + sprintf( szError, "Error when trying to destroy\n  %s vss file:\n", _szSpec );
		e->GetErrorMessage( p_szError, 1024 );
		
		AfxMessageBox( szError,  MB_ICONSTOP );
		return FALSE;
	END_CATCH_ALL

	return TRUE;
}


/*
 ----------------------------------------------------------------------------------------
  Description   : delete a file in VSS data base
  _szSpec             -> specif of file to delete
  Returns (BOOL ) TRUE if success
 ----------------------------------------------------------------------------------------
 */
BOOL OLE_fn_bDeleteFile( char *_szSpec )
{
	IVSSItem	oItem;

	if (!OLE_fn_bGetExistantItem( _szSpec, &oItem ) )
		return TRUE;

	TRY
		oItem.SetDeleted( TRUE );
	CATCH_ALL( e )
		char szError[1024];
		char *p_szError;

		p_szError = szError + sprintf( szError, "Error when trying to delete\n  %s vss file:\n", _szSpec );
		e->GetErrorMessage( p_szError, 1024 );
		
		AfxMessageBox( szError,  MB_ICONSTOP );
		return FALSE;
	END_CATCH_ALL

	return TRUE;
}

/*
 ----------------------------------------------------------------------------------------
  Description   : get last version of a file
  _szFileSpec         -> full vss file spec
  _p_oVersion         -> to return last version
  Returns (BOOL ) TRUE if success
 ----------------------------------------------------------------------------------------
 */
BOOL OLE_fn_bGetItemLastVersion( char *_szFileSpec, IVSSVersion *_p_oVersion )
{
	IVSSItem		oItem;
	long			lCurrentVersion;
	BOOL			bResult = FALSE;

	IVSSVersions	*p_oVersions;
	IEnumVARIANT	*p_oEnum;
	unsigned long	ulReturn;
	VARIANT			vVersion;
	
	if (!OLE_fn_bGetExistantItem( _szFileSpec, &oItem ) )
		return FALSE;
	lCurrentVersion = oItem.GetVersionNumber( );

	p_oVersions = (IVSSVersions *) oItem.GetVersions( 0 );
	p_oVersions->_NewEnum( (IUnknown **) &p_oEnum );

	p_oEnum->Reset();

	while (p_oEnum->Next( 1, &vVersion, &ulReturn ) == S_OK)
	{
		if (vVersion.vt == VT_DISPATCH )
		{
			_p_oVersion->AttachDispatch (vVersion.pdispVal);

			if (_p_oVersion->GetVersionNumber() == lCurrentVersion)
			{
				bResult = TRUE;
				break;
			}
			_p_oVersion->ReleaseDispatch();
		}
	}

	p_oEnum->Release();

	return bResult;
}

/*
 ----------------------------------------------------------------------------------------
  Description   : retrieve last version date for a file
  _szFileSpec         -> vss full file spec 
  xTime               -> to return time/date
  Returns (BOOL ) TRUE if success
 ----------------------------------------------------------------------------------------
 */
BOOL OLE_fn_bGetItemLastVersionDate( char *_szFileSpec, COleDateTime *p_oOleDate )
{
	IVSSVersion	oVersion;

	if ( !OLE_fn_bGetItemLastVersion( _szFileSpec, &oVersion ) )
		return FALSE;

	p_oOleDate->m_dt = oVersion.GetDate();
	return TRUE;
}

/*
 ----------------------------------------------------------------------------------------
  Description   : retrieve last version username
  _szFileSpec         -> vss full file spec 
  Returns (BOOL ) TRUE if success
 ----------------------------------------------------------------------------------------
 */
BOOL OLE_fn_bGetItemLastVersionUserName( char *_szFileSpec )
{
	IVSSVersion	oVersion;

	if ( !OLE_fn_bGetItemLastVersion( _szFileSpec, &oVersion ) )
		return FALSE;

	g_cNbUsers = 1;
	strcpy ( g_a_szUserName[0], (char*) (LPCTSTR) oVersion.GetUsername() );

	return TRUE;
}


/*
 =======================================================================================
  HIGH LEVEL FUNCTIONS
 =======================================================================================
 */

/*
 ----------------------------------------------------------------------------------------
  Description   : initialize vss database
  Returns (BOOL) TRUE if success, FALSE otherwise
 ----------------------------------------------------------------------------------------
 */
BOOL OLE_fn_bInitVss( void )
{
	if (!OLE_g_oDatabase.CreateDispatch( "SourceSafe" ))
	{
		AfxMessageBox("Unable to find SourceSafe OLE Server", MB_ICONSTOP);
		AfxThrowUserException();
		return FALSE;
	}
	return TRUE;
}


/*
 ----------------------------------------------------------------------------------------
  Description   : open vss database
  _szIniFile		-> name of initialisation file (with full path)
  Returns (BOOL) : TRUE if success, FALSE otherwise
 ----------------------------------------------------------------------------------------
 */
BOOL OLE_fn_bOpenVss( char *_szVssDatabase, char *_szUserName, char *_szPassword )
{
	TRY
		OLE_g_oDatabase.Open( _szVssDatabase, _szUserName, _szPassword );
	CATCH_ALL( e )
		char szError[1024];
		e->GetErrorMessage( szError, 1024 );
		AfxMessageBox( szError,  MB_ICONSTOP );
		OLE_g_oDatabase.ReleaseDispatch();
		OLE_fn_bInitVss();
		return FALSE;
	END_CATCH_ALL
	return TRUE;
}

/*
 ----------------------------------------------------------------------------------------
  Description   : open vss database
  _szIniFile		-> name of initialisation file (with full path)
  Returns (BOOL) : TRUE if success, FALSE otherwise
 ----------------------------------------------------------------------------------------
 */
BOOL OLE_fn_bVssLogin( CWnd *p_oFather )
{
	char			szPassword[100];
	CLoginDialog	oLoginDlg( p_oFather );
	
	oLoginDlg.m_fn_vSetUserName( g_stIniData.szVssUserName );
	oLoginDlg.m_fn_vSetDatabase( g_stIniData.szVssDatabase );

	while (1)
	{
		if ( oLoginDlg.DoModal() == IDOK )
		{
			strcpy( g_stIniData.szVssDatabase, oLoginDlg.m_fnp_szGetDatabase() );
			fn_IniD_vSetVssDatabase( g_stIniData.szVssDatabase );

			strcpy( g_stIniData.szVssUserName, oLoginDlg.m_fnp_szGetUserName() );
			fn_IniD_vSetVssUserName( g_stIniData.szVssUserName );
		
			strcpy( szPassword, oLoginDlg.m_fnp_szGetPassword() );

			if (OLE_fn_bOpenVss( g_stIniData.szVssDatabase, g_stIniData.szVssUserName, szPassword ) )
				return TRUE;
		}
		else
			return FALSE;
	}
}

/*
 ----------------------------------------------------------------------------------------
  Description   : get content of vss project
  _p_stVssProj        -> project to fill
  _szProjSpec         -> name of vss project
  _bOnlyProject       -> if TRUE get only project else get files and project
  Returns (BOOL) TRUE if sucess
 ----------------------------------------------------------------------------------------
 */
BOOL OLE_fn_bGetVssProjectContent( IVSSItem *_p_oVssItem, tdstProject *_p_stVssProj, BOOL _bOnlyProject, BOOL _bRecurse )
{
	LPDISPATCH  p_oDispatch;
	// project content var
	IVSSItems	oVssContent;
	long		lCount;
	// one content item var
	CString		oName;
	IVSSItem	*p_oVssOneItem;
	VARIANT		vItem;
	MSG			stMessage;
	
	IVSSItem	**d_oProjItem;
	long		lNbFile;
	long		lNbProj;


	if (g_hProjectWindow != NULL)
		SetWindowText( g_hProjectWindow, _p_stVssProj->szName );

	// get content of project
	p_oDispatch = _p_oVssItem->GetItems(0);
	if (p_oDispatch == NULL)
		return FALSE;
	oVssContent.AttachDispatch( p_oDispatch );

	// get count of project content
	lCount = oVssContent.GetCount();
	if (lCount == 0)
		return TRUE;

	// init variable
	vItem.vt = VT_I2;
	lNbFile = 0;
	lNbProj = 0;

	// allocate memory for temporary storage
	d_oProjItem = (IVSSItem **) malloc (lCount * sizeof( IVSSItem *) );

	// get number of files and project (or only project if _bOnlyProject )

	p_oVssOneItem = new IVSSItem;

	for (vItem.iVal = 1; vItem.iVal <= lCount; vItem.iVal ++)
	{
		if (PeekMessage( &stMessage, NULL,0 , 0, PM_REMOVE))
			DispatchMessage( &stMessage );

		p_oDispatch = oVssContent.GetItem( vItem );
		if (p_oDispatch == NULL)
			return FALSE;
		p_oVssOneItem->AttachDispatch( p_oDispatch );

		//lType = p_oVssOneItem->GetType();
		
		if ( p_oVssOneItem->GetType() == VSSITEM_PROJECT )
		{
			d_oProjItem[ lNbProj ] = p_oVssOneItem;
			
			oName = p_oVssOneItem->GetName();
			gs_d_szProj[ lNbProj ] = (char *) malloc( oName.GetLength() + 1 );
			strcpy ( gs_d_szProj[ lNbProj ], (char *) (LPCTSTR) oName );
			
			lNbProj ++;
			if (_bRecurse)
				p_oVssOneItem = new IVSSItem;
		}
		else 
			if (!_bOnlyProject)
			{
				oName = p_oVssOneItem->GetName();
				gs_d_szFile[ lNbFile ] = (char *) malloc( oName.GetLength() + 1 );
				strcpy ( gs_d_szFile[ lNbFile ], (char *) (LPCTSTR) oName );
				
				lNbFile ++;
			}
	}
	delete p_oVssOneItem;

	// allocate memory for all files and all sub projects
	if (lNbProj)
	{
		_p_stVssProj->lNumberOfSubProjects = lNbProj;
		_p_stVssProj->d_stSubProject = (tdstProject *) malloc ( lNbProj * sizeof( tdstProject) );
		for (lNbProj = 0; lNbProj < _p_stVssProj->lNumberOfSubProjects; lNbProj ++)
			fn_Tree_vInitProjectWithPointerName( &_p_stVssProj->d_stSubProject[ lNbProj ], gs_d_szProj[lNbProj] );
	}

	if ( lNbFile )
	{
		_p_stVssProj->lNumberOfFiles = lNbFile;

		if (lNbFile > 2048)
			AfxMessageBox( "more than 2048 files in a folder\r\nthere will soon be a big bug !!!\r\nContact me .\r\n", MB_ICONSTOP | MB_OK);
 
		_p_stVssProj->d_stFile = (tdstFile *) malloc ( lNbFile * sizeof( tdstFile) );
		for (lNbFile = 0; lNbFile < _p_stVssProj->lNumberOfFiles; lNbFile ++)
			fn_Tree_vInitFileWithPointerName( &_p_stVssProj->d_stFile[ lNbFile ], gs_d_szFile[ lNbFile ] );
	}

	// iterate again Ivss project content to construct sub project tree
	if (_bRecurse)
	{
		for (lNbProj = 0; lNbProj < _p_stVssProj->lNumberOfSubProjects; lNbProj ++)
		{
			if (PeekMessage( &stMessage, NULL,0 , 0, PM_REMOVE))
				DispatchMessage( &stMessage );

			OLE_fn_bGetVssProjectContent
				( 
					d_oProjItem[ lNbProj ], 
					&_p_stVssProj->d_stSubProject[lNbProj], 
					_bOnlyProject, 
					TRUE
				);
			delete (d_oProjItem[ lNbProj ] );
		}
	}

	free( d_oProjItem );
	
	return TRUE;
}


/*
 ----------------------------------------------------------------------------------------
  Description   : get project tree from vss
  _bOnlyProject        -> if TRUE get only project name else get project and file
  Returns (BOOL ) TRUE if success, FALSE otherwise
 ----------------------------------------------------------------------------------------
 */
BOOL OLE_fn_bGetVssProjectTree( BOOL _bOnlyProject, HWND _hProjectWindow )
{
	IVSSItem	oVssItem;
	LPDISPATCH  p_oDispatch;

	g_hProjectWindow = _hProjectWindow;

	if (g_p_stVssRootProject != NULL)
		fn_Tree_vFreeProjectTree(g_p_stVssRootProject, TRUE );

	// create and initialize root project
	g_p_stVssRootProject = (tdstProject *) malloc( sizeof (tdstProject) );
	fn_Tree_vInitProject( g_p_stVssRootProject, g_stIniData.szVssPath );
	
	TRY
		p_oDispatch = OLE_g_oDatabase.GetVSSItem( g_stIniData.szVssPath, 0 );
	CATCH_ALL(e)
		return FALSE;
	END_CATCH_ALL
	if (p_oDispatch == NULL)
		return FALSE;
	oVssItem.AttachDispatch( p_oDispatch );

	// allocate memory for name storage
	gs_d_szFile = (char **) malloc ( 2048 * sizeof( char *) );
	gs_d_szProj = (char **) malloc ( 2048 * sizeof( char *) );

	// get recursively and from root project vss tree
	OLE_fn_bGetVssProjectContent( &oVssItem, g_p_stVssRootProject, _bOnlyProject, TRUE );

	free( gs_d_szFile );
	free( gs_d_szProj );
	
	return TRUE;
}


/*
 ----------------------------------------------------------------------------------------
  Description   : refresh given vss project
  _szSpec             -> name of project
  _bRecurse           -> TRUE if refresh recursively
  _hProjectWindow     -> window were to put current project name
  Returns (BOOL ) TRUE if refresh success, FALSE else
 ----------------------------------------------------------------------------------------
 */
BOOL fn_bRefreshVssProjectTree( char *_szSpec, BOOL _bRecurse, HWND _hProjectWindow )
{
	tdstProject		*p_stVssProj;
	tdstProject		stNewProj;
	IVSSItem		oVssItem;
	
	p_stVssProj = fn_Tree_p_stGetProject( g_p_stVssRootProject, _szSpec );

	/*
	 * get new arborescence
	 */
	fn_Tree_vInitProject( &stNewProj, strrchr( _szSpec, '\\') + 1 );
	if (!OLE_fn_bGetExistantItem( _szSpec, &oVssItem ) )
		return FALSE;

	// allocate memory for name storage
	gs_d_szFile = (char **) malloc ( 2048 * sizeof( char *) );
	gs_d_szProj = (char **) malloc ( 2048 * sizeof( char *) );

	g_hProjectWindow = _hProjectWindow;

	// get recursively and from root project vss tree
	OLE_fn_bGetVssProjectContent( &oVssItem, &stNewProj, FALSE, _bRecurse );

	free( gs_d_szFile );
	free( gs_d_szProj );

	if (_bRecurse)
	{
		fn_Tree_vFreeProjectTree( p_stVssProj, FALSE );
		p_stVssProj->lNumberOfSubProjects = stNewProj.lNumberOfSubProjects;
		p_stVssProj->d_stSubProject = stNewProj.d_stSubProject;
		stNewProj.d_stSubProject = NULL;
	}
	else
	{
		fn_Tree_vFreeProjectFileList( p_stVssProj );
	}
	p_stVssProj->lNumberOfFiles = stNewProj.lNumberOfFiles;
	p_stVssProj->d_stFile = stNewProj.d_stFile;
	stNewProj.d_stFile = NULL;
	fn_Tree_vFreeProject( &stNewProj, TRUE );
	return TRUE;
}

/*
 ----------------------------------------------------------------------------------------
  Description   : Get file status
  _szFileSpec         -> name of file
  Returns (char ) status of file
 ----------------------------------------------------------------------------------------
 */
char OLE_fn_cGetVssFileStatus( char *_szFileSpec )
{
	LPDISPATCH		p_oDispatch;
	// current project var
	IVSSItem		oVssItem;
	IVSSCheckouts	oVssCheckouts;
	IVSSCheckout	oVssCheckout;
	long			lResult;
	VARIANT			vCheckout;

	// get vss item that correspond to the file spec
	if ( !OLE_fn_bGetExistantItem( _szFileSpec, &oVssItem ) )
		return VSSFILE_NOTFOUND;

	// get check out state of file
	lResult = oVssItem.GetIsCheckedOut();

	// if checked out get name of user that check out the file
	if (lResult != VSSFILE_NOTCHECKEDOUT)
	{
		p_oDispatch = oVssItem.GetCheckouts(); 
		oVssCheckouts.AttachDispatch( p_oDispatch );
		// get number of checkout
		g_cNbUsers = (char) oVssCheckouts.GetCount();
		vCheckout.vt = VT_I2;
		for ( vCheckout.iVal = 1; vCheckout.iVal <= g_cNbUsers ; vCheckout.iVal++ )
		{
			p_oDispatch = oVssCheckouts.GetItem( vCheckout );
			oVssCheckout.AttachDispatch( p_oDispatch );
			strcpy (g_a_szUserName[vCheckout.iVal - 1], oVssCheckout.GetUsername() );
		}

		return (char) lResult;
	}
	
	return VSSFILE_NOTCHECKEDOUT;
}


