void FProvider::LogErrors(const TArray<FString>& ErrorMessages)
{
	FMessageLog SourceControlLog(SourceControlLogName);
	for (auto It(ErrorMessages.CreateConstIterator()); It; ++It)
	{
		SourceControlLog.Error(FText::FromString(*It));
	}
}
void FSubversionSourceControlProvider::OutputCommandMessages(const FSubversionSourceControlCommand& InCommand) const
{
	FMessageLog SourceControlLog("SourceControl");

	for (int32 ErrorIndex = 0; ErrorIndex < InCommand.ErrorMessages.Num(); ++ErrorIndex)
	{
		SourceControlLog.Error(FText::FromString(InCommand.ErrorMessages[ErrorIndex]));
	}

	for (int32 InfoIndex = 0; InfoIndex < InCommand.InfoMessages.Num(); ++InfoIndex)
	{
		SourceControlLog.Info(FText::FromString(InCommand.InfoMessages[InfoIndex]));
	}
}
void FPerforceSourceControlProvider::OutputCommandMessages(const FPerforceSourceControlCommand& InCommand) const
{
	FMessageLog SourceControlLog("SourceControl");

	for (int32 ErrorIndex = 0; ErrorIndex < InCommand.ErrorMessages.Num(); ++ErrorIndex)
	{
		SourceControlLog.Error(InCommand.ErrorMessages[ErrorIndex]);
	}

	for (int32 InfoIndex = 0; InfoIndex < InCommand.InfoMessages.Num(); ++InfoIndex)
	{
		SourceControlLog.Info(InCommand.InfoMessages[InfoIndex]);
	}
}
bool FSubversionSourceControlProvider::TestConnection(const FString& RepositoryName, const FString& UserName, const FString& Password)
{
	FMessageLog SourceControlLog("SourceControl");

	// run a command on the server to see check connection.
	// If our credentials have not been cached then this will fail.
	TArray<FString> Files;
	Files.Add(FPaths::GameDir());
	TArray<class FXmlFile> ResultsXml;
	TArray<FString> Errors;

	bool bResult = SubversionSourceControlUtils::RunCommand(TEXT("info"), Files, TArray<FString>(), ResultsXml, Errors, UserName, Password);
	if(bResult)
	{
		SubversionSourceControlUtils::ParseInfoResults(ResultsXml, WorkingCopyRoot, RepositoryRoot);
	}

	// output any errors/results
	for(TArray<FString>::TConstIterator It = Errors.CreateConstIterator(); It; It++)
	{
		SourceControlLog.Warning(FText::FromString(*It));
	}

	if(bResult)
	{
		FFormatNamedArguments Arguments;
		Arguments.Add( TEXT("RepositoryName"), FText::FromString(RepositoryName) );
		SourceControlLog.Warning(FText::Format(LOCTEXT("ConnectionSuccess", "Successfully connected to repository {RepositoryName}"), Arguments));
	}
	else
	{
		FFormatNamedArguments Arguments;
		Arguments.Add( TEXT("RepositoryName"), FText::FromString(RepositoryName) );
		SourceControlLog.Warning(FText::Format(LOCTEXT("ConnectionFailed", "Failed to connect to repository {RepositoryName}"), Arguments));
	}

	return bResult;
}
bool FPerforceConnection::AutoDetectWorkspace(const FPerforceConnectionInfo& InConnectionInfo, FString& OutWorkspaceName)
{
	bool Result = false;
	FMessageLog SourceControlLog("SourceControl");

	//before even trying to summon the window, try to "smart" connect with the default server/username
	TArray<FText> ErrorMessages;
	FPerforceConnection Connection(InConnectionInfo);
	TArray<FString> ClientSpecList;
	Connection.GetWorkspaceList(InConnectionInfo, FOnIsCancelled(), ClientSpecList, ErrorMessages);

	//if only one client spec matched (and default connection info was correct)
	if (ClientSpecList.Num() == 1)
	{
		OutWorkspaceName = ClientSpecList[0];
		FFormatNamedArguments Arguments;
		Arguments.Add( TEXT("WorkspaceName"), FText::FromString(OutWorkspaceName) );
		SourceControlLog.Info(FText::Format(LOCTEXT("ClientSpecAutoDetect", "Auto-detected Perforce client spec: '{WorkspaceName}'"), Arguments));
		Result = true;
	}
	else if (ClientSpecList.Num() > 0)
	{
		SourceControlLog.Warning(LOCTEXT("AmbiguousClientSpecLine1", "Source Control unable to auto-login due to ambiguous client specs"));
		SourceControlLog.Warning(LOCTEXT("AmbiguousClientSpecLine2", "  Please select a client spec in the Perforce settings dialog"));
		SourceControlLog.Warning(LOCTEXT("AmbiguousClientSpecLine3", "  If you are unable to work with source control, consider checking out the files by hand temporarily"));

		// List out the clientspecs that were found to be ambiguous
		SourceControlLog.Info(LOCTEXT("AmbiguousClientSpecListTitle", "Ambiguous client specs..."));
		for (int32 Index = 0; Index < ClientSpecList.Num(); Index++)
		{
			FFormatNamedArguments Arguments;
			Arguments.Add( TEXT("ClientSpecName"), FText::FromString(ClientSpecList[Index]) );
			SourceControlLog.Info(FText::Format(LOCTEXT("AmbiguousClientSpecListItem", "...{ClientSpecName}"), Arguments));
		}
	}

	return Result;
}
bool FPerforceConnection::EnsureValidConnection(FString& InOutServerName, FString& InOutUserName, FString& InOutWorkspaceName, const FPerforceConnectionInfo& InConnectionInfo)
{
	bool bIsUnicodeServer = false;
	bool bConnectionOK = false;
#if USE_P4_API
	FMessageLog SourceControlLog("SourceControl");

	FString NewServerName = InOutServerName;
	FString NewUserName = InOutUserName;
	FString NewClientSpecName = InOutWorkspaceName;

	ClientApi TestP4;
	TestP4.SetProtocol("tag", "");
	TestP4.SetProtocol("enableStreams", "");

	if (NewServerName.Len() && NewUserName.Len() && NewClientSpecName.Len())
	{
		//attempt connection with given settings
		TestP4.SetPort(TCHAR_TO_ANSI(*NewServerName));

		if(InConnectionInfo.Password.Len() > 0)
		{
			TestP4.SetPassword(TCHAR_TO_ANSI(*InConnectionInfo.Password));
		}

		if(InConnectionInfo.HostOverride.Len() > 0)
		{
			TestP4.SetHost(TCHAR_TO_ANSI(*InConnectionInfo.HostOverride));
		}
	}

	Error P4Error;
	TestP4.Init(&P4Error);

	bConnectionOK = !P4Error.Test();
	if (!bConnectionOK)
	{
		//Connection FAILED
		StrBuf ErrorMessage;
		P4Error.Fmt(&ErrorMessage);
		SourceControlLog.Error(LOCTEXT("P4ErrorConnection", "P4ERROR: Failed to connect to source control provider."));
		SourceControlLog.Error(FText::FromString(ANSI_TO_TCHAR(ErrorMessage.Text())));
		FFormatNamedArguments Arguments;
		Arguments.Add( TEXT("PortName"), FText::FromString(NewServerName) );
		Arguments.Add( TEXT("UserName"), FText::FromString(NewUserName) );
		Arguments.Add( TEXT("ClientSpecName"), FText::FromString(NewClientSpecName) );
		Arguments.Add( TEXT("Ticket"), FText::FromString(InConnectionInfo.Ticket) );
		SourceControlLog.Error(FText::Format(LOCTEXT("P4ErrorConnection_Details", "Port={PortName}, User={UserName}, ClientSpec={ClientSpecName}, Ticket={Ticket}"), Arguments));
	}

	// run an info command to determine unicode status
	if(bConnectionOK)
	{
		TArray<FText> ErrorMessages;

		bConnectionOK = CheckUnicodeStatus(TestP4, bIsUnicodeServer, ErrorMessages);
		if(!bConnectionOK)
		{
			SourceControlLog.Error(LOCTEXT("P4ErrorConnection", "P4ERROR: Could not determine server unicode status."));
			SourceControlLog.Error(ErrorMessages.Num() > 0 ? ErrorMessages[0] : LOCTEXT("P4ErrorConnection_Unknown error", "Unknown error"));
			FFormatNamedArguments Arguments;
			Arguments.Add( TEXT("PortName"), FText::FromString(NewServerName) );
			Arguments.Add( TEXT("UserName"), FText::FromString(NewUserName) );
			Arguments.Add( TEXT("ClientSpecName"), FText::FromString(NewClientSpecName) );
			Arguments.Add( TEXT("Ticket"), FText::FromString(InConnectionInfo.Ticket) );
			SourceControlLog.Error(FText::Format(LOCTEXT("P4ErrorConnection_Details", "Port={PortName}, User={UserName}, ClientSpec={ClientSpecName}, Ticket={Ticket}"), Arguments));
		}
		else
		{
			if(bIsUnicodeServer)
			{
				// set translation mode. From here onwards we need to use UTF8 when using text args
				TestP4.SetTrans(CharSetApi::UTF_8);
			}

			// now we have determined unicode status, we can set the values that can be specified in non-ansi characters
			TestP4.SetCwd(FROM_TCHAR(*FPaths::RootDir(), bIsUnicodeServer));
			TestP4.SetUser(FROM_TCHAR(*NewUserName, bIsUnicodeServer));
			TestP4.SetClient(FROM_TCHAR(*NewClientSpecName, bIsUnicodeServer));

			if(InConnectionInfo.Ticket.Len())
			{
				TestP4.SetPassword(FROM_TCHAR(*InConnectionInfo.Ticket, bIsUnicodeServer));
			}
		}
	}

	if (bConnectionOK)
	{
		// If a client spec was not specified, attempt to auto-detect it here. If the detection is not successful, neither is this connection since we need a client spec.
		if ( NewClientSpecName.IsEmpty() )
		{
			FPerforceConnectionInfo AutoCredentials = InConnectionInfo;
			AutoCredentials.Port = TO_TCHAR(TestP4.GetPort().Text(), bIsUnicodeServer);
			AutoCredentials.UserName = TO_TCHAR(TestP4.GetUser().Text(), bIsUnicodeServer);

		 	bConnectionOK = FPerforceConnection::AutoDetectWorkspace(AutoCredentials, NewClientSpecName);
			if ( bConnectionOK )
			{
				TestP4.SetClient(FROM_TCHAR(*NewClientSpecName, bIsUnicodeServer));
			}
		}
	}

	if (bConnectionOK)
	{
		TArray<FText> ErrorMessages;

		bConnectionOK = TestConnection(TestP4, NewClientSpecName, bIsUnicodeServer, ErrorMessages);
		if (!bConnectionOK)
		{
			//Login FAILED
			SourceControlLog.Error(LOCTEXT("P4ErrorConnection", "P4ERROR: Failed to connect to source control provider."));
			SourceControlLog.Error(ErrorMessages.Num() > 0 ? ErrorMessages[0] : LOCTEXT("P4ErrorConnection_InvalidWorkspace", "Invalid workspace"));
			FFormatNamedArguments Arguments;
			Arguments.Add( TEXT("PortName"), FText::FromString(NewServerName) );
			Arguments.Add( TEXT("UserName"), FText::FromString(NewUserName) );
			Arguments.Add( TEXT("ClientSpecName"), FText::FromString(NewClientSpecName) );
			Arguments.Add( TEXT("Ticket"), FText::FromString(InConnectionInfo.Ticket) );
			SourceControlLog.Error(FText::Format(LOCTEXT("P4ErrorConnection_Details", "Port={PortName}, User={UserName}, ClientSpec={ClientSpecName}, Ticket={Ticket}"), Arguments));
		}
	}

	//whether successful or not, disconnect to clean up
	TestP4.Final(&P4Error);
	if (bConnectionOK && P4Error.Test())
	{
		//Disconnect FAILED
		bConnectionOK = false;
		StrBuf ErrorMessage;
		P4Error.Fmt(&ErrorMessage);
		SourceControlLog.Error(LOCTEXT("P4ErrorFailedDisconnect", "P4ERROR: Failed to disconnect from Server."));
		SourceControlLog.Error(FText::FromString(TO_TCHAR(ErrorMessage.Text(), bIsUnicodeServer)));
	}

	//if never specified, take the default connection values
	if (NewServerName.Len() == 0)
	{
		NewServerName = TO_TCHAR(TestP4.GetPort().Text(), bIsUnicodeServer);
	}
	if (NewUserName.Len() == 0)
	{
		NewUserName = TO_TCHAR(TestP4.GetUser().Text(), bIsUnicodeServer);
	}
	if (NewClientSpecName.Len() == 0)
	{
		NewClientSpecName = TO_TCHAR(TestP4.GetClient().Text(), bIsUnicodeServer);
		if (NewClientSpecName == TO_TCHAR(TestP4.GetHost().Text(), bIsUnicodeServer))
		{
			// If the client spec name is the same as host name, assume P4 couldn't get the actual
			// spec name for this host and let GetPerforceLogin() try to find a proper one.
			bConnectionOK = false;
		}
	}

	if (bConnectionOK)
	{
		InOutServerName = NewServerName;
		InOutUserName = NewUserName;
		InOutWorkspaceName = NewClientSpecName;
	}
#endif

	return bConnectionOK;
}