//
// Copyright 1997 Nicholas J. Irias.  All rights reserved.
//
//

// Cmd_Resolve.cpp

#include "stdafx.h"
#include "p4win.h"
#include "cmd_resolve.h"
#include "merge\GuiClientMerge.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif


IMPLEMENT_DYNCREATE(CCmd_Resolve, CP4Command)


CCmd_Resolve::CCmd_Resolve(CGuiClient *client) : CP4Command(client)
{
	m_ReplyMsg= WM_P4RESOLVE;
	m_TaskName= _T("Resolve Interactive");
	m_bHeadIsText = FALSE;	// TRUE means we know for sure, so init to FALSE
	m_BaseMergeFileName = _T("");
}

BOOL CCmd_Resolve::Run(LPCTSTR filespec, BOOL bForce, BOOL bTextualMerge)
{
	m_Resolved=FALSE;

	ClearArgs();
	AddArg(_T("resolve"));
	if (GET_SERVERLEVEL() >= 18)	// 2004.1 server or later?
		AddArg(_T("-o"));
	if (bForce)
		AddArg(_T("-f"));
	if (bTextualMerge)
		AddArg(_T("-t"));
	AddArg(m_filespec = filespec);

	return CP4Command::Run();
}

//////////////////////////////////////////////////////
// Butt-ugly handling of text messages for resolve operations
// Hopefully a tagged version of resolve will eliminate the need
//
void CCmd_Resolve::OnOutputInfo(char level, LPCTSTR data, LPCTSTR msg)
{
	CString temp;
	CString orgmsg = msg;

    TCHAR *pBase = StrStr(data, _T(" using base "));
	if(pBase)
	{
		m_BaseMergeFileName= pBase + StrLen(_T(" using base "));
		*pBase = _T('\0');
	}
    LPCTSTR pMerging = StrStr(data, _T(" - merging"));
    LPCTSTR pVs;
	if(pMerging)
	{
		TheApp()->StatusAdd(orgmsg);
		m_YourMergeFileName= CString(data, pMerging - data);
		m_TheirMergeFileName= pMerging + StrLen(_T(" - merging"));
	}
	else if( HandleBinaryMergeMessage(data) )
		TheApp()->StatusAdd(orgmsg);
	else if((pVs = StrStr(data, _T(" - vs"))) != 0)
	{
		TheApp()->StatusAdd(orgmsg);
		m_YourMergeFileName= CString(data, pVs - data);
		m_TheirMergeFileName= pVs + StrLen(_T(" - vs"));
	}
	else if(IsValidMergeMessage(data))
	{
		TheApp()->StatusAdd(orgmsg);
		m_Resolved = TRUE;
	}
	else
		CP4Command::OnOutputInfo(level, data, orgmsg);
}

int CCmd_Resolve::OnResolve(ClientMerge *m, Error *e)
{
    CGuiClientMerge merge(m);
	merge.SetFilespec(m_filespec);
	merge.SetHeadIsText(m_bHeadIsText);
    merge.SetBaseFileName(m_BaseMergeFileName);
    merge.SetYourFileName(m_YourMergeFileName);
    merge.SetTheirFileName(m_TheirMergeFileName);

    if(m->GetBaseFile())
	    ::PostMessage(GetReplyWnd(), WM_P4MERGE3, (WPARAM) &merge, GetServerKey());
    else
    	::PostMessage(GetReplyWnd(), WM_P4MERGE2, (WPARAM) &merge, GetServerKey());
    merge.WaitForSignal();
    return merge.GetStatus();
}

BOOL CCmd_Resolve::HandledCmdSpecificError(LPCTSTR errBuf, LPCTSTR errMsg)
{
    BOOL handledError=FALSE;
    
    if( StrStr(errBuf, _T("No file(s) to resolve") ))
    {
        // The gui does not consider this an error, so quell the output
        handledError=TRUE;
    }
	else if( StrStr(errBuf, _T("Cannot create a file when that file already exists") ))
	{
		// Give a more meaningful error dialog
		CString txt;
		txt.FormatMessage(IDS_CANTRENAMEISITLOCKED_s, m_YourMergeFileName);
		AfxMessageBox(txt, MB_ICONSTOP);
	}

    return handledError;
}


// Wrenched out of dmtypes.cc
static LPCTSTR DmtIntegHowFmt[] = 
{ 
	_T("merge from"),
	_T("merge into"),
	_T("branch from"),
	_T("branch into"), 
	_T("copy from"),
	_T("copy into"),
	_T("ignored"),
	_T("ignored by"), 
	_T("delete from"),
	_T("delete into"),
	_T("edit from"),
	_T("add from"),
};
#define NUM_MERGETYPES (sizeof(DmtIntegHowFmt)/sizeof(LPCTSTR))

BOOL CCmd_Resolve::IsValidMergeMessage( CString const& data)
{
	for(int i=0; i< NUM_MERGETYPES; i++)
	{
		if(data.Find(DmtIntegHowFmt[i]) != -1)
			return TRUE;		
	}
	return FALSE;
}


// Binary merge messages:
// The messages are formatted in DmResolveData::UserMessage( )
// If we find a first-half message immediately followed by
// a second half message, it is 'safe' to assume we have extracted
// the delimiter between their file and your file

static LPCTSTR FileTypeFirstHalf[] = 
{ 
	_T(" - text/"),
	_T(" - ctext/"),
	_T(" - cxtext/"),
	_T(" - ltext/"),
	_T(" - ktext/"),
	_T(" - ttext/"),
	_T(" - xtext/"),
	_T(" - xltext/"),
	_T(" - kxtext/"),
	_T(" - binary/"),
	_T(" - xbinary/"),
	_T(" - ubinary/"),
	_T(" - tempobj/"),
	_T(" - xtempobj/")
	_T(" - unicode/"),
	_T(" - xunicode/")
};

static LPCTSTR FileTypeSecondHalf[] = 
{ 
	_T("text merge "),
	_T("ctext merge "),
	_T("cxtext merge "),
	_T("ltext merge "),
	_T("ktext merge "),
	_T("ttext merge "),
	_T("xtext merge "),
	_T("xltext merge "),
	_T("kxtext merge "),
	_T("binary merge "),
	_T("xbinary merge "),
	_T("ubinary merge "),
	_T("tempobj merge "),
	_T("xtempobj merge ")
	_T("unicode merge "),
	_T("xunicode merge ")
};

#define NUM_MERGEFILETYPES (sizeof(FileTypeFirstHalf)/sizeof(LPCTSTR))

BOOL CCmd_Resolve::HandleBinaryMergeMessage( CString const& data )
{
    ASSERT(sizeof(FileTypeFirstHalf) == sizeof(FileTypeSecondHalf));

	int offset, len;

	for( int i=0; i < NUM_MERGEFILETYPES; i++ )
	{
		if( (offset= data.Find(FileTypeFirstHalf[i])) != -1 )
		{
			len= lstrlen(FileTypeFirstHalf[i]);
			CString txt2= data.Mid( offset + len );
			
			for( int j=0; j < NUM_MERGEFILETYPES; j++ )
			{
				if( txt2.Find( FileTypeSecondHalf[j]) == 0 )
				{
					len += lstrlen( FileTypeSecondHalf[j] );
					m_YourMergeFileName= data.Left( offset );
					m_TheirMergeFileName= data.Mid( offset + len );
					return TRUE;
				}
			}
		}
	}
	return FALSE;
}