// AssManMenu.cpp : Implementation of CAssManMenu
#include "stdafx.h" 
#include "OutputDialog.h"


#include "AssManShellExt.h"
#include "AssManMenu.h"
#include "ConfigManager.h"
/////////////////////////////////////////////////////////////////////////////
// CAssManMenu


//////////////////////////////////////////////////////////////////////////
//
// Function:    Initialize()
//
// Description:
//  Reads in the list of selected folders and stores them for later use.
//
//////////////////////////////////////////////////////////////////////////

HRESULT CAssManMenu::Initialize(LPCITEMIDLIST pidlFolder, LPDATAOBJECT  pDO, HKEY hProgID)
{
	try{
	
	FORMATETC fmt = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
	STGMEDIUM stg = { TYMED_HGLOBAL };
	HDROP     hDrop;
	TCHAR szFile[MAX_PATH];
	INITCOMMONCONTROLSEX iccex = { sizeof(INITCOMMONCONTROLSEX), ICC_DATE_CLASSES };
	// Init the common controls.
  InitCommonControlsEx(&iccex);
	
	m_bDoIt = FALSE;
	
	if (FAILED(pDO->GetData(&fmt, &stg)))
	{
		// Nope! Return an "invalid argument" error back to Explorer.
		return E_INVALIDARG;
	}
	
	// Get a pointer to the actual data.
  hDrop =(HDROP) GlobalLock(stg.hGlobal);
	
	// Make sure it worked.
	if (NULL == hDrop)
	{
		return E_INVALIDARG;
	}
	
	// Sanity check  make sure there is at least one filename.
	UINT uNumFiles = DragQueryFile(hDrop, 0xFFFFFFFF, NULL, 0);
	
	if (0 == uNumFiles)
	{
		GlobalUnlock(stg.hGlobal);
		ReleaseStgMedium(&stg);
		return E_INVALIDARG;
	}
	
	HRESULT hr = S_OK;	
	
	for (UINT uFile = 0; uFile < uNumFiles; uFile++)
	{ 
		if (0 == DragQueryFile(hDrop, uFile, szFile, MAX_PATH))
			continue;
		m_lsFiles.push_back(szFile);
	}
	char *sRootPath = (char *)_Module.m_pConfigManager->m_sBaseDir.c_str();
	//<<FIXME>> this check is enought
	m_bIsRootDir = FALSE;
	ATLTRACE("FILE =>> %s\n", szFile);
	int n=0;
	while(szFile[n]!=NULL)
	{
		if(szFile[n]=='\\')
			szFile[n]='/';
		n++;
	}
	
	if (!_strnicmp(_Module.m_pConfigManager->m_sBaseDir.c_str(), szFile, _tcslen(_Module.m_pConfigManager->m_sBaseDir.c_str())))
	{
		m_bDoIt = TRUE;
		if (!_tcscmp(szFile, _Module.m_pConfigManager->m_sBaseDir.c_str()))
		{
			ATLTRACE("ROOT DIR =>> %s\n", szFile);
			m_bIsRootDir = TRUE;
		}
	}
	else 
	{
		m_bIsRootDir = FALSE;
		m_bDoIt = FALSE;
	}
	
	GlobalUnlock(stg.hGlobal);
  ReleaseStgMedium(&stg);
	
	return hr;
	}
	catch(...)
	{
		ATLTRACE("ERROR Initialize\n");
		return E_FAIL;
	}
}

//////////////////////////////////////////////////////////////////////////
//
// Function:    QueryContextMenu()
//
// Description:
//  Adds our items to the supplied menu.
//
//////////////////////////////////////////////////////////////////////////

HRESULT CAssManMenu::QueryContextMenu(HMENU hmenu, UINT uMenuIndex, UINT  uidFirstCmd, UINT uidLastCmd, UINT  uFlags)
{
	try{
	m_uBaseCommand = uidFirstCmd;
	// If the flags include CMF_DEFAULTONLY then we shouldn't do anything.
	if (!m_bDoIt)
		return MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, 0);
	if (uFlags & CMF_DEFAULTONLY)
	{
		return MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, 0);
	}
	
	
	HMENU hAssMan = CreatePopupMenu();
	MenuCategoryListItor catItor;
	catItor = _Module.m_pConfigManager->m_lstCategories.begin();
	
	unsigned long nMenuEntryPos = 0;
	unsigned long nMenuPos = 0;
	InsertMenu(hmenu, uMenuIndex++, MF_SEPARATOR | MF_BYPOSITION, 0, NULL);  
	InsertMenu(hmenu, uMenuIndex++, MF_STRING | MF_POPUP | MF_BYPOSITION, 
		(UINT_PTR)hAssMan, _T("AssMan"));
	SetMenuItemBitmaps(hmenu, uMenuIndex, MF_BYPOSITION, m_hCheckInBmp, NULL);
	
	while (catItor != _Module.m_pConfigManager->m_lstCategories.end())
	{
		MenuProjectListItor projItor;
		HMENU hProject = CreatePopupMenu();
		projItor = catItor->lstMenus.begin();
		nMenuPos = 0;
		while (projItor != catItor->lstMenus.end())
		{
			_AddMenuItem(hProject, projItor->sCaption.c_str(), nMenuPos, m_uBaseCommand + projItor->nMenuID, m_hCheckInBmp);
			nMenuPos++;
			++projItor;
		}
		InsertMenu(hAssMan, nMenuEntryPos, MF_STRING | MF_POPUP | MF_BYPOSITION, 
			(UINT_PTR)hProject, catItor->sCaption.c_str());
		nMenuEntryPos++;
		++catItor;
	}
	// The return value tells the shell how many top-level items we added.
	
	return MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, nMenuPos + m_uBaseCommand - 1);
	}catch(...)
	{
		ATLTRACE("ERROR QueryContextMenu\n");
		return E_FAIL;
	}
}

//////////////////////////////////////////////////////////////////////////
//
// Function:    GetCommandString()
//
// Description:
//  Sets the flyby help string for the Explorer status bar.
//
//////////////////////////////////////////////////////////////////////////


HRESULT CAssManMenu::GetCommandString(UINT  uCmdID, UINT uFlags, UINT* puReserved, LPSTR szName, UINT  cchMax)
{
	try{
		LPCTSTR szPrompt;
		
		USES_CONVERSION;
		UINT uCommand = uCmdID;
		if (uFlags & GCS_HELPTEXT)
		{
			switch (uCommand)
			{
			case ID_MENU_CHECK_IN:
				szPrompt = _T("CheckIn all selected files");
				break;
				
			case ID_MENU_CHECK_OUT:
				szPrompt = _T("CheckOut all selected files");
				break;
			case ID_MENU_GET_LATEST_VERSION:
				szPrompt = _T("Get Latest Version");
				break;
			default:
				//ATLASSERT(0);           // should never get here
				return E_INVALIDARG;
				break;
			}
			
			// Copy the help text into the supplied buffer.  If the shell wants
			// a Unicode string, we need to case szName to an LPCWSTR.
			
			if (uFlags & GCS_UNICODE)
			{
				lstrcpynW((LPWSTR) szName, T2CW(szPrompt), cchMax);
			}
			else
			{
				lstrcpynA(szName, T2CA(szPrompt), cchMax);
			}
		}
		else if (uFlags & GCS_VERB)
		{
			// Copy the verb name into the supplied buffer.  If the shell wants
			// a Unicode string, we need to case szName to an LPCWSTR.
			
			switch (uCommand)
			{
			case ID_MENU_CHECK_IN:
				if (uFlags & GCS_UNICODE)
				{
					lstrcpynW((LPWSTR) szName, L"CheckIn", cchMax);
				}
				else
				{
					lstrcpynA(szName, "CheckIn", cchMax);
				}
				break;
				
			case ID_MENU_CHECK_OUT:
				if (uFlags & GCS_UNICODE)
				{
					lstrcpynW((LPWSTR) szName, L"CheckOut", cchMax);
				}
				else
				{
					lstrcpynA(szName, "CheckOut", cchMax);
				}
				break;
			case ID_MENU_GET_LATEST_VERSION:
				if (uFlags & GCS_UNICODE)
				{
					lstrcpynW((LPWSTR) szName, L"GetLatestVersion", cchMax);
				}
				else
				{
					lstrcpynA(szName, "GetLatestVersion", cchMax);
				}
				break;
			default:
				ATLASSERT(0);           // should never get here
				return E_INVALIDARG;
				break;
			}
		}
	}
	catch(...)
	{
		return E_FAIL;
	}
	return S_OK;
}

//////////////////////////////////////////////////////////////////////////
//
// Function:    InvokeCommand()
//
// Description:
//  Carries out the selected command.
//
//////////////////////////////////////////////////////////////////////////

HRESULT CAssManMenu::InvokeCommand(LPCMINVOKECOMMANDINFO pInfo)
{
	try{
		//////////////////////////////////////////////////////////////////////////							
		ATLTRACE("CAssManMenu::InvokeCommand\n");
		if (0 != HIWORD(pInfo->lpVerb))
			return E_INVALIDARG;
		
		
		unsigned long nID = LOWORD(pInfo->lpVerb);
		MenuCategoryListItor catItor;
		catItor = _Module.m_pConfigManager->m_lstCategories.begin();
		while (catItor != _Module.m_pConfigManager->m_lstCategories.end())
		{
			MenuProjectListItor projItor;
			projItor = catItor->lstMenus.begin();
			while (projItor != catItor->lstMenus.end())
			{
				if (projItor->nMenuID == nID)
				{
					//////////////////////////////////////////////////////////////////////////
					//////////////////////////////////////////////////////////////////////////					
					ATLTRACE("**********************%s********************", projItor->sCaption.c_str());
					m_sCmdDatabase = projItor->sVSSDatabase;
					m_sCmdProjFolder = projItor->sVSSProjPath;
					m_sCmdDestFolder = projItor->sDestinationFolder;
					m_bCmdRecursive= projItor->bRecursive;
					
					m_dlg.m_pCmdInfo = pInfo;
					m_dlg.m_hReady = m_hReady;
					_Module.m_bAbort=false;
					ResetEvent(m_hReady);
					HANDLE hThread=CreateThread(NULL, NULL, CAssManMenu::_WorkingThread, this, NULL, NULL);
					m_dlg.m_hThread=hThread;
					if(m_dlg.DoModal()!=IDCANCEL && hThread){
						::TerminateThread(hThread,0xDEADBEEF);
						//////////////////////////////////////////////////////////////////////////					
						//////////////////////////////////////////////////////////////////////////					
					}
					CloseHandle(m_hReady);
					return S_OK;
				}
				++projItor;
			}
			
			++catItor;
		}
		//////////////////////////////////////////////////////////////////////////					
	}catch(_com_error &e){
		return e.Error();		
	}
	catch(...){
		return E_FAIL;
	}
	return E_INVALIDARG;
}



bool CAssManMenu::_AddMenuItem(HMENU hMenu, _String sName, UINT nIndex, UINT nCmd, HBITMAP hBitmap)
{
	InsertMenu(hMenu, nIndex, MF_STRING | MF_BYPOSITION, nCmd, sName.c_str());
	SetMenuItemBitmaps(hMenu, nCmd, MF_BYCOMMAND, hBitmap, NULL);
	return true;
}

HMENU CAssManMenu::_AddSubMenu(HMENU hParent, _String name, UINT nIndex, UINT nCmd, HBITMAP hBitmap)
{
	HMENU hNewMenu =CreatePopupMenu(); 
	InsertMenu(hParent, nIndex, MF_POPUP | MF_BYPOSITION, (UINT)hNewMenu, name.c_str());
	SetMenuItemBitmaps(hParent, nIndex, MF_BYPOSITION, hBitmap, NULL);
	return hNewMenu;
}

DWORD WINAPI CAssManMenu::_WorkingThread(LPVOID lpParameter)
{
	CAssManMenu *pThis = (CAssManMenu *)lpParameter;
	pThis->WorkingThread();
	return 0;
}


void CAssManMenu::WorkingThread()
{
	try{
		
		ATLTRACE("void CAssManMenu::WorkingThread()\n");
		::CoInitialize(NULL);
		_String sResult;
		if (::WaitForSingleObject(m_hReady, 3000) != WAIT_OBJECT_0)
			return;
		
		ResetEvent(m_hReady);
		GetFromVSS(m_sCmdDatabase, m_sCmdProjFolder, m_sCmdDestFolder);
		// do stuff and store the result in sResult
		ATLTRACE("if(_Module.m_bAbort!=true)\n");
		if(_Module.m_bAbort!=true){
			m_dlg.SetCurrFile((TCHAR *)"DONE!!  DONE!!  DONE!!  DONE!!  DONE!!  DONE!!  DONE!!  DONE!!  DONE!!  DONE!!  DONE!!");
			m_dlg.SetCompleted();
		}
		ATLTRACE("CoUninitialize\n");
		::CoUninitialize();
		ATLTRACE("Bau\n");
		SetEvent(m_hReady);
		ATLTRACE("Thread Finito\n");
	}catch(...)
	{
		SetEvent(m_hReady);
		ATLTRACE("ERROR Thread Finito\n");
	}
	
}

void CAssManMenu::TraverseFolder(IVSSItemPtr pItem, _bstr_t sFolder)
{
	try
	{
		IVSSItemsPtr pItemColl;
		pItemColl = pItem->GetItems(VARIANT_FALSE);
		LONG nCount;
		nCount = pItemColl->Count;
		
		if (nCount)
		{
			for (LONG n = 1; n <= nCount; n++)
			{
				//this is the safer mode to terminare the thread
				if(_Module.m_bAbort==true){
					ATLTRACE("TraverseFolder Abort\n");
					break;
				} 
				_bstr_t sPath;
				IVSSItemPtr pItem,pItemTemp;
				pItem = pItemColl->GetItem(n);
				pItemTemp = pItemColl->GetItem(n);
				
				switch (pItem->GetType())
				{
				case VSSITEM_FILE:
					ATLTRACE("FILE>>>%s/%s\n", (TCHAR *)sFolder, (TCHAR *)pItem->GetName());
					sPath=sFolder+"/"+pItem->GetName();
					m_dlg.SetCurrFile((TCHAR *)sPath);
					try
					{
						bool bSkip=false;
						TCHAR *sTempPath=(TCHAR *)sPath;
						long nStatus;
						if(!FAILED(pItem->get_IsCheckedOut(&nStatus)))
						{
							if(nStatus==VSSFILE_CHECKEDOUT_ME)
							{
								bSkip=true;
								m_dlg.AddDlgResult((TCHAR *)(sPath), _T("skipped(checked out by you)"));
							}
							
						}
						
						
						if(bSkip!=true)
						{
							SkipListItor itor=_Module.m_pConfigManager->m_lstSkip.begin();
							for(itor=_Module.m_pConfigManager->m_lstSkip.begin();
							itor!=_Module.m_pConfigManager->m_lstSkip.end();
							++itor)
							{
								_bstr_t sSkip=(*itor).c_str();
								_bstr_t sExt=(&sTempPath[sPath.length()-sSkip.length()]);
								if(sPath.length()>sSkip.length())
								{
									if(sExt==sSkip)
									{
										bSkip=true;
										m_dlg.AddDlgResult((TCHAR *)(sPath), _T("skipped"));
										break; 
									}
								} 
							}
						}
						if(bSkip==false)
						{
							bool bGet=false;
							FILE *f=NULL;
							
							if(PathFileExists((TCHAR *)sPath))
							{
								//fclose(f);
							}
							else
							{
								bGet=true;
							} 

							///////////////
							if(bGet==false)
								if(pItem->GetIsDifferent(sPath)==VARIANT_TRUE){
									bGet=true;
								}
								///////////////
								if(bGet==true){
									pItem->Get(NULL, VSSFLAG_REPREPLACE | VSSFLAG_TIMEMOD | VSSFLAG_RECURSYES | VSSFLAG_FORCEDIRNO);
									if(_Module.m_bAbort!=true)
										m_dlg.AddDlgResult((TCHAR *)(sPath), _T("succeded"));
								}
								///////////////	
						}
							
								
					}
					catch (_com_error &e)
					{
						ATLTRACE("ERROR %s\n",(TCHAR *)e.Description());
						if(_Module.m_bAbort!=true)
							m_dlg.AddDlgResult((TCHAR *)(sPath), (TCHAR *)e.Description());
					}
					break;
				case VSSITEM_PROJECT:
					{
						_bstr_t sTempFolder=pItem->GetName();
						if(((TCHAR *)sTempFolder)[0]==_T('_'))
						{
							ATLTRACE("SKIPPING>>>%s\n", (TCHAR *)pItem->GetName());
							break;
						}
						ATLTRACE("FOLDER>>>%s\n", (TCHAR *)pItem->GetName());
						
						
						sTempFolder = sFolder + _bstr_t("/") + pItem->GetName();
						pItem->PutLocalSpec(sTempFolder);
						if(m_bCmdRecursive)
							TraverseFolder(pItem, sTempFolder);
					}
					break;
				default:
					break;
				}
			}
		}
	}catch (_com_error &e)
	{
		if(_Module.m_bAbort!=true)
			m_dlg.AddDlgResult(_T("<<<critical error>>>"), (TCHAR *)e.Description());
	}
}


void CAssManMenu::GetFromVSS(_String sDatasbase, _String sProjFolder, _String sDestFolder) 
{
	try
	{
		IVSSDatabasePtr pDatabase;
		IVSSItemPtr pIRootItem;
		IVSSItemsPtr pItemColl;
		_String sTempBaseFolder;
		pDatabase.CreateInstance(_T("SourceSafe"));
		pDatabase->Open(sDatasbase.c_str(), _T(""), _T(""));
		pIRootItem = pDatabase->GetVSSItem(sProjFolder.c_str(), VARIANT_FALSE);
		if(sDestFolder.empty()==true)
			sTempBaseFolder = _Module.m_pConfigManager->m_sBaseDir;
		else
			sTempBaseFolder = _Module.m_pConfigManager->m_sBaseDir + _T("/")+sDestFolder;
		pIRootItem->PutLocalSpec(sTempBaseFolder.c_str());
		TraverseFolder(pIRootItem, sTempBaseFolder.c_str());
				
	}
	catch (_com_error &e)
	{
		m_dlg.AddDlgResult(_T("<<<critical error>>>"), (TCHAR *)e.Description());
	}
}

