#include "VideoBackendLifecycle.h"

VideoBackendLifecycleState VideoBackendLifecycle::State() const
{
	return mState;
}

const std::string& VideoBackendLifecycle::FailureReason() const
{
	return mFailureReason;
}

VideoBackendLifecycleTransition VideoBackendLifecycle::TransitionTo(VideoBackendLifecycleState next, const std::string& reason)
{
	VideoBackendLifecycleTransition transition;
	transition.previous = mState;
	transition.current = next;
	transition.reason = reason;
	transition.accepted = CanTransition(mState, next);
	if (!transition.accepted)
	{
		transition.current = mState;
		transition.errorMessage = std::string("Invalid video backend lifecycle transition from ") +
			StateName(mState) + " to " + StateName(next) + ".";
		return transition;
	}

	mState = next;
	transition.current = mState;
	if (mState != VideoBackendLifecycleState::Failed)
		mFailureReason.clear();
	return transition;
}

VideoBackendLifecycleTransition VideoBackendLifecycle::Fail(const std::string& reason)
{
	VideoBackendLifecycleTransition transition = TransitionTo(VideoBackendLifecycleState::Failed, reason);
	if (transition.accepted)
		mFailureReason = reason;
	return transition;
}

bool VideoBackendLifecycle::CanTransition(VideoBackendLifecycleState current, VideoBackendLifecycleState next)
{
	if (current == next)
		return true;

	switch (current)
	{
	case VideoBackendLifecycleState::Uninitialized:
		return next == VideoBackendLifecycleState::Discovering ||
			next == VideoBackendLifecycleState::Stopped ||
			next == VideoBackendLifecycleState::Failed;
	case VideoBackendLifecycleState::Discovering:
		return next == VideoBackendLifecycleState::Discovered ||
			next == VideoBackendLifecycleState::Failed;
	case VideoBackendLifecycleState::Discovered:
		return next == VideoBackendLifecycleState::Configuring ||
			next == VideoBackendLifecycleState::Stopped ||
			next == VideoBackendLifecycleState::Failed;
	case VideoBackendLifecycleState::Configuring:
		return next == VideoBackendLifecycleState::Configured ||
			next == VideoBackendLifecycleState::Failed;
	case VideoBackendLifecycleState::Configured:
		return next == VideoBackendLifecycleState::Prerolling ||
			next == VideoBackendLifecycleState::Stopped ||
			next == VideoBackendLifecycleState::Failed;
	case VideoBackendLifecycleState::Prerolling:
		return next == VideoBackendLifecycleState::Running ||
			next == VideoBackendLifecycleState::Stopping ||
			next == VideoBackendLifecycleState::Failed;
	case VideoBackendLifecycleState::Running:
		return next == VideoBackendLifecycleState::Degraded ||
			next == VideoBackendLifecycleState::Stopping ||
			next == VideoBackendLifecycleState::Failed;
	case VideoBackendLifecycleState::Degraded:
		return next == VideoBackendLifecycleState::Running ||
			next == VideoBackendLifecycleState::Stopping ||
			next == VideoBackendLifecycleState::Failed;
	case VideoBackendLifecycleState::Stopping:
		return next == VideoBackendLifecycleState::Stopped ||
			next == VideoBackendLifecycleState::Failed;
	case VideoBackendLifecycleState::Stopped:
		return next == VideoBackendLifecycleState::Discovering ||
			next == VideoBackendLifecycleState::Failed;
	case VideoBackendLifecycleState::Failed:
		return next == VideoBackendLifecycleState::Stopped ||
			next == VideoBackendLifecycleState::Discovering;
	default:
		return false;
	}
}

const char* VideoBackendLifecycle::StateName(VideoBackendLifecycleState state)
{
	switch (state)
	{
	case VideoBackendLifecycleState::Uninitialized:
		return "uninitialized";
	case VideoBackendLifecycleState::Discovering:
		return "discovering";
	case VideoBackendLifecycleState::Discovered:
		return "discovered";
	case VideoBackendLifecycleState::Configuring:
		return "configuring";
	case VideoBackendLifecycleState::Configured:
		return "configured";
	case VideoBackendLifecycleState::Prerolling:
		return "prerolling";
	case VideoBackendLifecycleState::Running:
		return "running";
	case VideoBackendLifecycleState::Degraded:
		return "degraded";
	case VideoBackendLifecycleState::Stopping:
		return "stopping";
	case VideoBackendLifecycleState::Stopped:
		return "stopped";
	case VideoBackendLifecycleState::Failed:
		return "failed";
	default:
		return "unknown";
	}
}
