#ifndef GST_OptionalHelpers_hpp__
#define GST_OptionalHelpers_hpp__

#include <boost/optional.hpp>

namespace GST
{
namespace Utils
{
namespace detail
{
template<class T>
struct NotNegativeValue
{
	bool operator()(const T &val) const
	{
		return val >= 0;
	}
};

template<class T>
struct PositiveValue
{
	bool operator()(const T &val) const
	{
		return val > 0;
	}
};

template<class T>
struct NotEmptyValue
{
	bool operator()(const T &val) const
	{
		return !val.empty();
	}
};
} // namespace detail

// these methods are meant as internal helper, so no dll export here

template<class T, class P>
BOOST_DEDUCED_TYPENAME boost::optional<T>::reference_const_type
get_optional_value_if_or(
	const boost::optional<T> &opt,
	P predicate,
	BOOST_DEDUCED_TYPENAME boost::optional<T>::reference_const_type
		defaultValue)
{
	if(opt && predicate(opt.get()))
	{
		return opt.get();
	}
	else
	{
		return defaultValue;
	}
}

// returns value if value >= 0, otherwise defaultValue
template<class T>
BOOST_DEDUCED_TYPENAME boost::optional<T>::reference_const_type
get_optional_value_not_negative_or(
	const boost::optional<T> &opt,
	BOOST_DEDUCED_TYPENAME boost::optional<T>::reference_const_type
		defaultValue)
{
	return get_optional_value_if_or(
		opt, detail::NotNegativeValue<T>(), defaultValue);
}

// returns value if value > 0, otherwise defaultValue
template<class T>
BOOST_DEDUCED_TYPENAME boost::optional<T>::reference_const_type
get_optional_value_positive_or(
	const boost::optional<T> &opt,
	BOOST_DEDUCED_TYPENAME boost::optional<T>::reference_const_type
		defaultValue)
{
	return get_optional_value_if_or(
		opt, detail::PositiveValue<T>(), defaultValue);
}

// returns value if !value.empty(), otherwise defaultValue
template<class T>
BOOST_DEDUCED_TYPENAME boost::optional<T>::reference_const_type
get_optional_value_not_empty_or(
	const boost::optional<T> &opt,
	BOOST_DEDUCED_TYPENAME boost::optional<T>::reference_const_type
		defaultValue)
{
	return get_optional_value_if_or(
		opt, detail::NotEmptyValue<T>(), defaultValue);
}

// returns value if value is set, otherwise defaultValue
using boost::get_optional_value_or;
} // namespace Utils
} // namespace GST

#endif // GST_OptionalHelpers_hpp__
