/** 
 * Main entry point for accessing an online subsystem by name
 * Will load the appropriate module if the subsystem isn't currently loaded
 * It's possible that the subsystem doesn't exist and therefore can return NULL
 *
 * @param SubsystemName - name of subsystem as referenced by consumers
 * @return Requested online subsystem, or NULL if that subsystem was unable to load or doesn't exist
 */
IOnlineSubsystem* FOnlineSubsystemModule::GetOnlineSubsystem(const FName InSubsystemName)
{
	FName SubsystemName = InSubsystemName;
	if (SubsystemName == NAME_None)
	{
		SubsystemName = DefaultPlatformService;
	}

	IOnlineSubsystem** OSSFactory = NULL;
	if (SubsystemName != NAME_None)
	{
		OSSFactory = PlatformServices.Find(SubsystemName);
		if (OSSFactory == NULL)
		{
			// Attempt to load the requested factory
			TSharedPtr<IModuleInterface> NewModule = LoadSubsystemModule(SubsystemName.ToString());
			if( NewModule.IsValid() )
			{
				// If the module loaded successfully this should be non-NULL;
				OSSFactory = PlatformServices.Find(SubsystemName);
			}
			if (OSSFactory == NULL)
			{
				UE_LOG(LogOnline, Warning, TEXT("Unable to load OnlineSubsystem module %s"), *InSubsystemName.ToString());
			}
		}
	}

	return (OSSFactory == NULL) ? NULL : *OSSFactory;
}
/**
 * Called right after the module DLL has been loaded and the module object has been created
 * Overloaded to allow the default subsystem a chance to load
 */
void FOnlineSubsystemModule::StartupModule()
{
	FString InterfaceString;

	// Load the platform defined "default" online services module
	if (GConfig->GetString(TEXT("OnlineSubsystem"), TEXT("DefaultPlatformService"), InterfaceString, GEngineIni) &&
		InterfaceString.Len() > 0)
	{
		FName InterfaceName = FName(*InterfaceString);
		if (LoadSubsystemModule(InterfaceString).IsValid() && PlatformServices.Contains(InterfaceName))
		{
			DefaultPlatformService = InterfaceName;
		}
		else
		{
			UE_LOG(LogOnline, Warning, TEXT("Unable to load default OnlineSubsystem module %s, using NULL interface"), *InterfaceString);
			InterfaceString = TEXT("Null");
			InterfaceName = FName(*InterfaceString);
			if (LoadSubsystemModule(InterfaceString).IsValid() && PlatformServices.Contains(InterfaceName))
			{
				DefaultPlatformService = InterfaceName;
			}
		}
	}
	else
	{
		UE_LOG(LogOnline, Warning, TEXT("No default platform service specified for OnlineSubsystem"));
	}
}
void FOnlineSubsystemModule::LoadDefaultSubsystem()
{
	FString InterfaceString;

	// look up the OSS name from the .ini. 
	// first, look in a per-platform key (DefaultPlatformService_INIPLATNAME)
	FString BaseKeyName = TEXT("DefaultPlatformService");
	FString PlatformKeyName = BaseKeyName + TEXT("_") + FPlatformProperties::IniPlatformName();

	// Load the platform defined "default" online services module
	if (GConfig->GetString(TEXT("OnlineSubsystem"), *PlatformKeyName, InterfaceString, GEngineIni) == false ||
		InterfaceString.Len() == 0)
	{
		GConfig->GetString(TEXT("OnlineSubsystem"), *BaseKeyName, InterfaceString, GEngineIni);
	}

	if (InterfaceString.Len() > 0)
	{
		FName InterfaceName = FName(*InterfaceString);
		// A module loaded with its factory method set for creation and a default instance of the online subsystem is required
		if (LoadSubsystemModule(InterfaceString).IsValid() &&
			OnlineFactories.Contains(InterfaceName) &&
			GetOnlineSubsystem(InterfaceName) != NULL)
		{
			DefaultPlatformService = InterfaceName;
		}
		else
		{
			UE_LOG(LogOnline, Log, TEXT("Unable to load default OnlineSubsystem module %s, using NULL interface"), *InterfaceString);
			InterfaceString = TEXT("Null");
			InterfaceName = FName(*InterfaceString);

			// A module loaded with its factory method set for creation and a default instance of the online subsystem is required
			if (LoadSubsystemModule(InterfaceString).IsValid() &&
				OnlineFactories.Contains(InterfaceName) &&
				GetOnlineSubsystem(InterfaceName) != NULL)
			{
				DefaultPlatformService = InterfaceName;
			}
		}
	}
	else
	{
		UE_LOG(LogOnline, Log, TEXT("No default platform service specified for OnlineSubsystem"));
	}
}
IOnlineSubsystem* FOnlineSubsystemModule::GetOnlineSubsystem(const FName InSubsystemName)
{
	FName SubsystemName, InstanceName;
	FName KeyName = ParseOnlineSubsystemName(InSubsystemName, SubsystemName, InstanceName);

	IOnlineSubsystemPtr* OnlineSubsystem = NULL;
	if (SubsystemName != NAME_None)
	{
		OnlineSubsystem = OnlineSubsystems.Find(KeyName);
		if (OnlineSubsystem == NULL)
		{
			IOnlineFactory** OSSFactory = OnlineFactories.Find(SubsystemName);
			if (OSSFactory == NULL)
			{
				// Attempt to load the requested factory
				TSharedPtr<IModuleInterface> NewModule = LoadSubsystemModule(SubsystemName.ToString());
				if (NewModule.IsValid())
				{
					// If the module loaded successfully this should be non-NULL
					OSSFactory = OnlineFactories.Find(SubsystemName);
				}
			}

			if (OSSFactory != NULL)
			{
				IOnlineSubsystemPtr NewSubsystemInstance = (*OSSFactory)->CreateSubsystem(InstanceName);
				if (NewSubsystemInstance.IsValid())
				{
					OnlineSubsystems.Add(KeyName, NewSubsystemInstance);
					OnlineSubsystem = OnlineSubsystems.Find(KeyName);
				}
				else
				{
						bool* bNotedPreviously = OnlineSubsystemFailureNotes.Find(KeyName);
						if (!bNotedPreviously || !(*bNotedPreviously))
						{
							UE_LOG(LogOnline, Log, TEXT("Unable to create OnlineSubsystem module %s"), *SubsystemName.ToString());
							OnlineSubsystemFailureNotes.Add(KeyName, true);
						}
					}
				}
			}
	}

	return (OnlineSubsystem == NULL) ? NULL : (*OnlineSubsystem).Get();
}