#pragma once

namespace YAML
{
	// implementation for Node::Read
	// (the goal is to call ConvertScalar if we can, and fall back to operator >> if not)
	// thanks to litb from stackoverflow.com
	// http://stackoverflow.com/questions/1386183/how-to-call-a-templated-function-if-it-exists-and-something-else-otherwise/1386390#1386390

	// Note: this doesn't work on gcc 3.2, but does on gcc 3.4 and above. I'm not sure about 3.3.
	
#if __GNUC__ && (__GNUC__ < 3 || (__GNUC__ == 3 && __GNUC_MINOR__ <= 3))
	// trick doesn't work? Just fall back to ConvertScalar.
	// This means that we can't use any user-defined types as keys in a map
	template <typename T>
	inline bool Node::Read(T& value) const {
		return ConvertScalar(*this, value);
	}
#else
	// usual case: the trick!
	template<bool>
	struct read_impl;
	
	// ConvertScalar available
	template<>
	struct read_impl<true> {
		template<typename T>
		static bool read(const Node& node, T& value) {
			return ConvertScalar(node, value);
		}
	};

	// ConvertScalar not available
	template<>
	struct read_impl<false> {
		template<typename T>
		static bool read(const Node& node, T& value) {
			try {
				node >> value;
			} catch(const Exception&) {
				return false;
			}
			return true;
		}
	};
	
	namespace fallback {
		// sizeof > 1
		struct flag { char c[2]; };
		flag Convert(...);
		
		int operator,(flag, flag);
		
		template<typename T>
		char operator,(flag, T const&);
		
		char operator,(int, flag);
		int operator,(char, flag);
	}

	template <typename T>
	inline bool Node::Read(T& value) const {
		using namespace fallback;

		return read_impl<sizeof (fallback::flag(), Convert(std::string(), value), fallback::flag()) != 1>::read(*this, value);
	}
#endif // done with trick
	
	// the main conversion function
	template <typename T>
	inline bool ConvertScalar(const Node& node, T& value) {
		std::string scalar;
		if(!node.GetScalar(scalar))
			return false;
		
		return Convert(scalar, value);
	}
}
