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

// Cmd_Diff2.cpp

#include "stdafx.h"
#include "p4win.h"
#include "cmd_diff2.h"
#include "cmd_prepbrowse.h"
#include "cmd_where.h"

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


IMPLEMENT_DYNCREATE(CCmd_Diff2, CP4Command)


CCmd_Diff2::CCmd_Diff2(CGuiClient *client) : CP4Command(client)
{
	m_ReplyMsg= WM_P4DIFF2;
	m_TaskName= _T("Diff2");
}


BOOL CCmd_Diff2::Run(LPCTSTR file1, LPCTSTR file2, 
					 int rev1, int rev2, 
					 CString &fileType1, CString &fileType2,
					 BOOL bLocal1, BOOL bLocal2, BOOL bDoIt/*=FALSE*/)
{
	// Record the args
	m_FileName[0]=file1;
	m_FileName[1]=file2;
	m_FileRev[0]=rev1;
	m_FileRev[1]=rev2;
	m_FileType[0]=fileType1;
	m_FileType[1]=fileType2;
	m_LocalFlag[0]=bLocal1;
	m_LocalFlag[1]=bLocal2;
	m_DoIt=bDoIt;

	if (bDoIt)
	{
		ClearArgs();
		AddArg(_T("diff2"));
		AddArg(_T("-q"));
		AddArg(m_FileName[0]);
		AddArg(m_FileName[1]);
	}
	
	return CP4Command::Run();
}

void CCmd_Diff2::PreProcess(BOOL& done)
{
	m_InfoText.Empty();

	// If we are going to actually run the command on the server
	// then there is no preprocessing to do.
	if (m_DoIt)
	{
		done=FALSE;
		return;
	}

	int i;
	Error e;
	CString fn1;
	CString fn2;
	BOOL isTextual1;
	BOOL isTextual2;
	BOOL isUnicode1;
	BOOL isUnicode2;
	BOOL isUtf161;
	BOOL isUtf162;
	BOOL success;

	// Get the first file
	if (m_FileRev[0] >= 0 && (i = m_FileName[0].FindOneOf(_T("@#"))) != -1)
		m_FileName[0] = m_FileName[0].Left(i);
	if (!m_LocalFlag[0])
	{
		CCmd_PrepBrowse cmd1(m_pClient);
		cmd1.Init(NULL, RUN_SYNC, HOLD_LOCK);
		success= cmd1.Run(m_FileName[0], m_FileType[0], m_FileRev[0]);
		cmd1.CloseConn(&e);
		m_FatalError= cmd1.GetError();
		m_ErrorTxt= cmd1.GetErrorText();
		if(	!success || m_FatalError || cmd1.NoFileAtThatRev() )
		{
			done=TRUE;
			return;
		}
		fn1 = cmd1.GetTempName();
		isTextual1 = cmd1.GetTempFile()->IsTextual();
		isUnicode1 = cmd1.GetTempFile()->IsUnicode();
		isUtf161 = (cmd1.GetTempFile()->GetType() & FST_MASK) == FST_UTF16;
	}
	else
	{
		if (m_FileName[0].GetAt(1) != _T(':'))
		{
			success = FALSE;
			CCmd_Where cmd(m_pClient);
			cmd.Init(NULL, RUN_SYNC, HOLD_LOCK);
			if ( cmd.Run(m_FileName[0]) && !cmd.GetError() 
			  && cmd.GetDepotFiles()->GetCount() )
			{
				m_FileName[0] = cmd.GetLocalSyntax();
				success = TRUE;
			}
			cmd.CloseConn(&e);
			if(	!success )
			{
				m_FatalError = TRUE;
				m_ErrorTxt.FormatMessage(IDS_UNABLE_TO_CONVERT_s_TO_LOCAL_SYNTAX, m_FileName[0]);
				done=TRUE;
				return;
			}
		}
		fn1 = m_FileName[0].GetBuffer(m_FileName[0].GetLength()+1);
		isUtf161 = (m_FileType[0].Find(_T("utf16")) != -1);
		isUnicode1 =  isUtf161 || (m_FileType[0].Find(_T("unicode")) != -1);
		isTextual1 = isUnicode1 || (m_FileType[0].Find(_T("text")) != -1);
	}
    
	// Get the second file
	if (m_FileRev[1] >= 0 && (i = m_FileName[1].FindOneOf(_T("@#"))) != -1)
		m_FileName[1] = m_FileName[1].Left(i);
	if (!m_LocalFlag[1])
	{
		CCmd_PrepBrowse cmd2(m_pClient);
		cmd2.Init(NULL, RUN_SYNC, HOLD_LOCK);
		success= cmd2.Run(m_FileName[1], m_FileType[1], m_FileRev[1]);
		cmd2.CloseConn(&e);
		m_FatalError= cmd2.GetError();
		m_ErrorTxt= cmd2.GetErrorText();
		if(	!success || m_FatalError  || cmd2.NoFileAtThatRev() )
		{
			done=TRUE;
			return;
		}
		fn2 = cmd2.GetTempName();
		isTextual2 = cmd2.GetTempFile()->IsTextual();
		isUnicode2 = cmd2.GetTempFile()->IsUnicode();
		isUtf162 = (cmd2.GetTempFile()->GetType() & FST_MASK) == FST_UTF16;
	}
	else
	{
		if (m_FileName[1].GetAt(1) != _T(':'))
		{
			success = FALSE;
			CCmd_Where cmd(m_pClient);
			cmd.Init(NULL, RUN_SYNC, HOLD_LOCK);
			if ( cmd.Run(m_FileName[1]) && !cmd.GetError() 
			  && cmd.GetDepotFiles()->GetCount() )
			{
				m_FileName[1] = cmd.GetLocalSyntax();
				success = TRUE;
			}
			cmd.CloseConn(&e);
			if(	!success )
			{
				m_FatalError = TRUE;
				m_ErrorTxt.FormatMessage(IDS_UNABLE_TO_CONVERT_s_TO_LOCAL_SYNTAX, m_FileName[1]);
				done=TRUE;
				return;
			}
		}
		fn2 = m_FileName[1].GetBuffer(m_FileName[1].GetLength()+1);
		isUtf162 = (m_FileType[1].Find(_T("utf16")) != -1);
		isUnicode2 =  isUtf161 || (m_FileType[1].Find(_T("unicode")) != -1);
		isTextual2 = isUnicode2 || (m_FileType[1].Find(_T("text")) != -1);
	}

	// check to see if we have a binary filetype for either one of the files
	// and if so, has the user specified their own diff program and does it handle binary files
	// if using p4diff or their diff doesn't handle binary, just use internal Compare function
	//
	// If dealing with binary files, get the file extension, if any,
	// and find out if it has an associated diff for that extension
	CString appName;
	appName.Empty();
	BOOL b = (!isTextual1 || !isTextual2) && !GET_P4REGPTR()->GetDiffAppIsBinary();
	if ( b )
	{
		CString extension = GetFilesExtension(fn2);
		if(!extension.IsEmpty())
			appName= GET_P4REGPTR()->GetAssociatedDiff(extension);
	}
	if ( b && appName.IsEmpty() )
	{
		FileSys *f1 = FileSys::Create( FST_BINARY );
		FileSys *f2 = FileSys::Create( FST_BINARY );
		f1->Set( CharFromCString(fn1) );
		f2->Set( CharFromCString(fn2) );
	    if( f1->Compare( f2, &e ) )
		{
			m_InfoText.Format(_T("Binary files differ but unable to display diff:\n\n%s,\n%s"), 
				m_FileName[0], m_FileName[1]);
			TheApp()->StatusAdd(m_InfoText);
			if (m_Output2Dlg)
				m_InfoText.Empty();
		}
		else
		{
			m_InfoText.Format(_T("Binary files identical:\n\n%s,\n%s"), 
				m_FileName[0], m_FileName[1]);
			TheApp()->StatusAdd(m_InfoText);
			if (m_Output2Dlg)
				m_InfoText.Empty();
		}
		delete f1;
		delete f2;
	}
	else	// both are text  or  user's diff can handle binary files
	{
		CString errorText;
		CString buf1;
		CString buf2;
		BOOL isUnicode = isUnicode1 + isUnicode2;
		if (isUnicode)
		{
			if (isUnicode != 2)
			{
				if (IDYES != AfxMessageBox(IDS_UNICODETEXTMIX, MB_ICONQUESTION|MB_DEFBUTTON2|MB_YESNO))
				{
					done=TRUE;
					return;
				}
			}
			if (isUtf161 || isUtf162)
				isUnicode = 16;
		}
		if (m_FileRev[0] > 0)
			buf1.Format(_T("%s#%ld"), m_FileName[0], m_FileRev[0]);
		else
			buf1.Format(_T("%s"), m_FileName[0]);
		if (m_FileRev[1] > 0)
			buf2.Format(_T("%s#%ld"), m_FileName[1], m_FileRev[1]);
		else
			buf2.Format(_T("%s"), m_FileName[1]);
		if( !TheApp()->RunApp(DIFF_APP, RA_NOWAIT, NULL, isUnicode, NULL, 
								errorText, fn1, fn2, _T("-l"), buf1, _T("-r"), buf2) )
		TheApp()->StatusAdd(errorText, SV_ERROR );
	}

	// Note:
	// By setting done=TRUE, we prevent the main ExecCommand loop from running,
	// so this command will consist only of the subcommands that were invoked
	// in PreProcess()
	done=TRUE;
}

void CCmd_Diff2::OnOutputInfo(char level, LPCTSTR data, LPCTSTR msg)
{
	if (m_DoIt && level == _T('0'))
	{
		if (m_Output2Dlg)
			m_InfoText += CString(msg) + _T('\n');
		else
			TheApp()->StatusAdd(msg);
	}
	else
		CP4Command::OnOutputInfo(level, data, msg);
}

BOOL CCmd_Diff2::HandledCmdSpecificError(LPCTSTR errBuf, LPCTSTR errMsg )
{
	if ( StrStr(errBuf, _T("No file(s) to diff")) )
	{
		TheApp()->StatusAdd(m_Output2Dlg ? LoadStringResource(IDS_NOFILESDIFFER) 
										 : errMsg, SV_COMPLETION);
		return TRUE ; 
	}
	return ( FALSE );
}