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

// Cmd_Add.cpp

#include "stdafx.h"
#include "p4win.h"
#include "Cmd_Add.h"
#include "Cmd_Fstat.h"
#include "Cmd_Opened.h"

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


	
IMPLEMENT_DYNCREATE(CCmd_Add, CP4Command)


CCmd_Add::CCmd_Add(CGuiClient *client) : CP4Command(client)
{
	m_ReplyMsg= WM_P4ADD;
	m_TaskName= _T("Add");
	m_OpenAction = 0;
}


BOOL CCmd_Add::Run(int changeNum, CStringList *files, CStringList *files2edit)
{
	if (files2edit)		// Save off any files that are to be edited
	{
		for (POSITION pos= files2edit->GetHeadPosition(); pos!=NULL; )
			m_Str2Edit.AddTail(files2edit->GetNext(pos));
	}

	m_pStrListIn= files;
	m_posStrListIn= m_pStrListIn->GetHeadPosition();
	m_ChangeNum= changeNum;

	ClearArgs();	
	m_BaseArgs=AddArg(_T("add"));

	if (GET_SERVERLEVEL() >= 18)	// always use -f for 2004.2 or later servers
		m_BaseArgs=AddArg(_T("-f"));

	if(changeNum)
	{
		AddArg(_T("-c"));
        m_BaseArgs=AddArg(m_ChangeNum);
	}
	NextListArgs();

	return CP4Command::Run();
}

void CCmd_Add::PostProcess()
{
	if(m_StrListOut.GetCount() > MAX_FILESEEKS)
	{
		// If there are too many files, do not waste time
		// gathering info for an incremental window update
		m_HitMaxFileSeeks= TRUE;
		TheApp()->StatusAdd(_T("CCmd_Add hit MAX_FILESEEKS - blowing off incremental update"), SV_DEBUG);
	}
	else if(GET_SERVERLEVEL() >= 19)			// 2005.1 or later?
	{
     	// Set up and run fstat synchronously
		CStringList strList;
		strList.AddHead(_T("//..."));
		CCmd_Fstat cmd0(m_pClient);
		cmd0.Init(NULL, RUN_SYNC);
		cmd0.SetIncludeAddedFiles( TRUE );
		if(cmd0.Run( FALSE, &strList, TRUE, 0, TRUE, m_ChangeNum ))
		{
			m_FatalError= cmd0.GetError();
			MergeOpenInfo(cmd0.GetFileList());
		}
	}
	else
	{
		// Set up and run Opened synchronously
		CCmd_Opened cmd(m_pClient);
		cmd.Init(NULL, RUN_SYNC);
		if(cmd.Run(FALSE))
		{
			m_FatalError= cmd.GetError();
			MergeOpenInfo(cmd.GetList());
		}
		else
		{
			m_ErrorTxt= _T("Unable to Run Opened");
			m_FatalError=TRUE;
		}
	}
}

void CCmd_Add::MergeOpenInfo(CObList *pOpenList)
{
	// The names of added files are in m_StrListOut
	// Rummage through the list of my open files, pOpenList,
	// and remove all files that are not on the added files list.
	// TODO: revisit this procedure.  both lists are alphabetical, so
	// there should be a performance gain if we walk the lists together	
	// instead of comparing each item in the first list w/ each item in the
	// second list

	CP4FileStats *stats;
	POSITION posStrList, lastPos;
	POSITION posOpenList= pOpenList->GetHeadPosition();
	CString openName;
	CString addName;
	int compLen;
	BOOL found;

	// Go top to bottom thru openlist
	while( posOpenList != NULL )
	{
		lastPos=posOpenList;
		// Get the depot filename
		stats= (CP4FileStats *) pOpenList->GetNext(posOpenList);
		openName=stats->GetFullDepotPath();
		openName+= _T('#');
		compLen=openName.GetLength();
		found=FALSE;

		posStrList= m_StrListOut.GetHeadPosition();
		while(posStrList != NULL)
		{
			addName=m_StrListOut.GetNext(posStrList);
			if(_tcsncmp(openName, addName, compLen)==0)
			{
				found=TRUE;
				break;
			}
		}
		if(!found)
		{
			delete stats;
			pOpenList->RemoveAt(lastPos);
		}

	} // while posOpenList


	// Finally, transfer the pOpenList pointers to our own ObList,
	// because pOpenList will dissappear when its command goes out of scope
	posOpenList= pOpenList->GetHeadPosition();
	while( posOpenList != NULL )
		m_List.AddHead( pOpenList->GetNext(posOpenList) );
}

void CCmd_Add::OnOutputInfo(char level, LPCTSTR data, LPCTSTR msg)
{
	if(StrStr(data, _T("opened for add")))
	{
		if(!StrStr(data, _T("currently opened for add")))
		{
			m_StrListOut.AddHead(data);
			return;
		}
	}
	else if (m_OpenAction)	// 1 == Edit Only; 2 == Add & Edit
	{
        LPCTSTR pos;
		if ((pos = StrStr(data, _T(" - can't add existing file"))) != 0)
		{
			m_Str2Edit.AddHead(CString(data, pos-data));
			return;
		}
		else if ((pos = StrStr(data, _T("can't add (already opened for edit)"))) != 0)
		{
            // remove "can't add(" and ")", leaving only "already opened for edit"
			CString txt(data, pos-data-1);
			txt += _T("already opened for edit");
            CP4Command::OnOutputInfo(level, txt, data == msg ? txt : msg);
            return;
		}
		else if (StrStr(data, _T(" - warning: add of existing file")) != 0)
			return;
	}

	CP4Command::OnOutputInfo(level, data, msg);
}