#ifndef K3DSDK_PERSISTENCE_PRIVATE_H
#define K3DSDK_PERSISTENCE_PRIVATE_H

// K-3D
// Copyright (c) 1995-2004, Timothy M. Shead
//
// Contact: tshead@k-3d.com
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public
// License along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

/** \file
		\brief Declares the k3d::persistence::container and related classes used to automate serialization of data objects
		\author Tim Shead (tshead@k-3d.com)
*/

#include <boost/filesystem/path.hpp>

// Forward declarations
namespace sdpxml { class Document; }
namespace sdpxml { class Element; }
namespace k3d { template<typename, typename> class object_adaptor; }
namespace k3d { template<typename> class shader_adaptor; }

namespace k3d
{

namespace implementation_private
{

/////////////////////////////////////////////////////////////////////////////
// to_string

/// Converts any stream-serializeable type into a string
template<class data_t>
const std::string to_string(const data_t& Value)
{
	std::ostringstream buffer;
	buffer << Value;

	return buffer.str();
}

/////////////////////////////////////////////////////////////////////////////
// to_string<bool>

/// Specialization of to_string() for converting a bool to a string
inline const std::string to_string(const bool Value)
{
	std::ostringstream buffer;
	buffer << (Value ? "true" : "false");

	return buffer.str();
}

/////////////////////////////////////////////////////////////////////////////
// to_string<boost::filesystem::path>

/// Specialization of to_string() for converting boost::filesystem::path to a string
inline const std::string to_string(const boost::filesystem::path& Value)
{
	return Value.native_file_string();
}

/////////////////////////////////////////////////////////////////////////////
// from_string

/// Converts a string into any stream-serializable type
template<class data_t>
const data_t from_string(const sdpString Value, const data_t& DefaultValue)
{
	data_t result(DefaultValue);
	std::istringstream buffer(Value.c_str());
	buffer >> result;

	return result;
}

/////////////////////////////////////////////////////////////////////////////
// from_string<bool>

/// Specialization of from_string() for converting an sdpString to a bool
inline const bool from_string(const sdpString Value, const bool DefaultValue)
{
	bool result = DefaultValue;

	if(0 == Value.find("true"))
		result = true;
	else if(0 == Value.find("false"))
		result = false;

/** \todo Update this when gcc 3.0 becomes ubiquitous
	std::istringstream stream(Value.c_str());
	stream >> std::boolalpha >> result;
*/

	return result;
}

/////////////////////////////////////////////////////////////////////////////
// from_string<sdpString>

/// Specialization of from_string() for converting string types
inline const sdpString from_string(const sdpString Value, const sdpString& DefaultValue)
{
	return Value;
}

/////////////////////////////////////////////////////////////////////////////
// from_string<std::string>

/// Specialization of from_string() for converting string types
inline const std::string from_string(const sdpString Value, const std::string& DefaultValue)
{
	return Value;
}

/////////////////////////////////////////////////////////////////////////////
// from_string<boost::filesystem::path>

/// Specialization of from_string() for converting to boost::filesystem::path
inline const boost::filesystem::path from_string(const sdpString Value, const boost::filesystem::path& DefaultValue)
{
	return boost::filesystem::path(Value, boost::filesystem::native);
}

/////////////////////////////////////////////////////////////////////////////
// generic_data_proxy

/// Implementation of k3d::persistence::idata_proxy that can serialize any object that supports the name() and value() concepts
template<typename data_t>
class generic_data_proxy :
	public k3d::persistence::idata_proxy
{
public:
	generic_data_proxy(data_t& Data) :
		m_data(Data)
	{
	}

	const std::string name()
	{
		return m_data.name();
	}

	void load(sdpxml::Document& Document, sdpxml::Element& Element)
	{
		m_data.value() = from_string(sdpxml::GetAttribute<sdpString>(Element, "value", ""), m_data.value());
	}

	void load_complete()
	{
	}

	void save(sdpxml::Element& Element, k3d::idependencies& Dependencies)
	{
		Element.Append(sdpxml::Element("variable", "", sdpxml::Attribute("name", m_data.name()), sdpxml::Attribute("value", k3d::implementation_private::to_string(m_data.value()))));
	}

private:
	data_t& m_data;
};

/////////////////////////////////////////////////////////////////////////////
// object_data_proxy

/// Implementation of k3d::persistence::idata_proxy that can serialize k3d::object_adaptor objects
template<typename data_t>
class object_data_proxy :
	public k3d::persistence::idata_proxy
{
public:
	object_data_proxy(data_t& Data) :
		m_data(Data)
	{
	}

	const std::string name()
	{
		return m_data.name();
	}

	void load(sdpxml::Document& Document, sdpxml::Element& Element)
	{
		m_data.value() = from_string(sdpxml::GetAttribute<sdpString>(Element, "value", ""), m_data.value());
	}

	void load_complete()
	{
		m_data.load_complete();
	}

	void save(sdpxml::Element& Element, k3d::idependencies& Dependencies)
	{
		Element.Append(sdpxml::Element("variable", "", sdpxml::Attribute("name", m_data.name()), sdpxml::Attribute("value", k3d::implementation_private::to_string(m_data.value()))));
	}

private:
	 data_t& m_data;
};

} // namespace implementation_private

} // namespace k3d

#endif // !K3DSDK_PERSISTENCE_PRIVATE_H


