#include "OpenGLComposite.h"
#include "RuntimeCoordinator.h"
#include "RuntimeJson.h"
#include "RuntimeServices.h"
#include "RuntimeStore.h"
#include "RuntimeUpdateController.h"

std::string OpenGLComposite::GetRuntimeStateJson() const
{
	return mRuntimeStore ? mRuntimeStore->BuildPersistentStateJson() : "{}";
}

unsigned short OpenGLComposite::GetControlServerPort() const
{
	return mRuntimeStore ? mRuntimeStore->GetConfiguredControlServerPort() : 0;
}

unsigned short OpenGLComposite::GetOscPort() const
{
	return mRuntimeStore ? mRuntimeStore->GetConfiguredOscPort() : 0;
}

std::string OpenGLComposite::GetOscBindAddress() const
{
	return mRuntimeStore ? mRuntimeStore->GetConfiguredOscBindAddress() : "127.0.0.1";
}

std::string OpenGLComposite::GetControlUrl() const
{
	return "http://127.0.0.1:" + std::to_string(GetControlServerPort()) + "/";
}

std::string OpenGLComposite::GetDocsUrl() const
{
	return "http://127.0.0.1:" + std::to_string(GetControlServerPort()) + "/docs";
}

std::string OpenGLComposite::GetOscAddress() const
{
	return "udp://" + GetOscBindAddress() + ":" + std::to_string(GetOscPort()) + " /VideoShaderToys/{Layer}/{Parameter}";
}

bool OpenGLComposite::AddLayer(const std::string& shaderId, std::string& error)
{
	return mRuntimeCoordinator &&
		mRuntimeUpdateController &&
		mRuntimeUpdateController->ApplyRuntimeCoordinatorResult(mRuntimeCoordinator->AddLayer(shaderId), &error);
}

bool OpenGLComposite::RemoveLayer(const std::string& layerId, std::string& error)
{
	return mRuntimeCoordinator &&
		mRuntimeUpdateController &&
		mRuntimeUpdateController->ApplyRuntimeCoordinatorResult(mRuntimeCoordinator->RemoveLayer(layerId), &error);
}

bool OpenGLComposite::MoveLayer(const std::string& layerId, int direction, std::string& error)
{
	return mRuntimeCoordinator &&
		mRuntimeUpdateController &&
		mRuntimeUpdateController->ApplyRuntimeCoordinatorResult(mRuntimeCoordinator->MoveLayer(layerId, direction), &error);
}

bool OpenGLComposite::MoveLayerToIndex(const std::string& layerId, std::size_t targetIndex, std::string& error)
{
	return mRuntimeCoordinator &&
		mRuntimeUpdateController &&
		mRuntimeUpdateController->ApplyRuntimeCoordinatorResult(mRuntimeCoordinator->MoveLayerToIndex(layerId, targetIndex), &error);
}

bool OpenGLComposite::SetLayerBypass(const std::string& layerId, bool bypassed, std::string& error)
{
	return mRuntimeCoordinator &&
		mRuntimeUpdateController &&
		mRuntimeUpdateController->ApplyRuntimeCoordinatorResult(mRuntimeCoordinator->SetLayerBypass(layerId, bypassed), &error);
}

bool OpenGLComposite::SetLayerShader(const std::string& layerId, const std::string& shaderId, std::string& error)
{
	return mRuntimeCoordinator &&
		mRuntimeUpdateController &&
		mRuntimeUpdateController->ApplyRuntimeCoordinatorResult(mRuntimeCoordinator->SetLayerShader(layerId, shaderId), &error);
}

bool OpenGLComposite::UpdateLayerParameterJson(const std::string& layerId, const std::string& parameterId, const std::string& valueJson, std::string& error)
{
	JsonValue parsedValue;
	if (!ParseJson(valueJson, parsedValue, error))
		return false;

	return mRuntimeCoordinator &&
		mRuntimeUpdateController &&
		mRuntimeUpdateController->ApplyRuntimeCoordinatorResult(mRuntimeCoordinator->UpdateLayerParameter(layerId, parameterId, parsedValue), &error);
}

bool OpenGLComposite::UpdateLayerParameterByControlKeyJson(const std::string& layerKey, const std::string& parameterKey, const std::string& valueJson, std::string& error)
{
	JsonValue parsedValue;
	if (!ParseJson(valueJson, parsedValue, error))
		return false;

	return mRuntimeCoordinator &&
		mRuntimeUpdateController &&
		mRuntimeUpdateController->ApplyRuntimeCoordinatorResult(mRuntimeCoordinator->UpdateLayerParameterByControlKey(layerKey, parameterKey, parsedValue), &error);
}

bool OpenGLComposite::ResetLayerParameters(const std::string& layerId, std::string& error)
{
	return mRuntimeCoordinator &&
		mRuntimeUpdateController &&
		mRuntimeUpdateController->ApplyRuntimeCoordinatorResult(mRuntimeCoordinator->ResetLayerParameters(layerId), &error);
}

bool OpenGLComposite::SaveStackPreset(const std::string& presetName, std::string& error)
{
	return mRuntimeCoordinator &&
		mRuntimeUpdateController &&
		mRuntimeUpdateController->ApplyRuntimeCoordinatorResult(mRuntimeCoordinator->SaveStackPreset(presetName), &error);
}

bool OpenGLComposite::LoadStackPreset(const std::string& presetName, std::string& error)
{
	return mRuntimeCoordinator &&
		mRuntimeUpdateController &&
		mRuntimeUpdateController->ApplyRuntimeCoordinatorResult(mRuntimeCoordinator->LoadStackPreset(presetName), &error);
}
