#ifndef _OBJECT_ARCHIVE_H_
#define _OBJECT_ARCHIVE_H_

#include <Geometry/IFileSerialisable.h>
#include <Geometry/SRS.h>
#include <Geometry/SRSItem.h>
#include <Geometry/boost_serialize_includes.hpp>
#include <Utils/Converter.h>
#include <buildspec.h>
#include <map>

#include <boost/pointer_cast.hpp>
#include <boost/shared_ptr.hpp>

namespace GST
{
namespace Geometry
{

struct GST_API_EXPORT ObjectArchive
{
	ObjectArchive();

	typedef std::map<std::string, std::string, Utils::UpperCaseCompare>
		VariousPropertyMap;

	///@name members (Do not forget to change class version when adding a new
	/// one)
	//@{
	std::string objectName;
	std::string geometryFile;
	IFileSerialisable::FileType geometryFileType;
	std::string propertyFile;
	std::string lockid;
	Geometry::SRSPtr srs;
	VariousPropertyMap various_properties;
	std::string original_name;
	//@}

	///@name getters/setters
	//@{
	bool isLocked() const;
	void addProperty(const std::string &key, const std::string &value);
	void removeProperty(const std::string &key);
	std::string getValue(const std::string &key);
	std::string ToIdentityString() const;
	void updateRelativePathsToGlobalPath(const std::string &globalPath,
										 bool throwIfLinkedFilesAreNotExistent
										 = true);
	//@}

	/// to file
	void toFile(const std::string &filename);
	static boost::shared_ptr<ObjectArchive> FromFile(
		const std::string &filename,
		bool throwIfLinkedFilesAreNotExistent = true);

	/// boost serialization access
	template<typename Archive>
	void serialize(Archive &ar, const unsigned int version);
};
typedef boost::shared_ptr<ObjectArchive> ObjArchivePtr;

template<typename Archive>
void ObjectArchive::serialize(Archive &ar, const unsigned int version)
{
	ar &BOOST_SERIALIZATION_NVP(objectName);
	ar &BOOST_SERIALIZATION_NVP(geometryFile);
	ar &BOOST_SERIALIZATION_NVP(geometryFileType);
	ar &BOOST_SERIALIZATION_NVP(propertyFile);
	ar &BOOST_SERIALIZATION_NVP(lockid);

	registerSRSTypes<Archive>(ar);
	if(Archive::is_saving::value)
	{
		if(srs && srs->getType() == SRS::GSTID)
		{
			// make a copy to base class
			GSTSRSRefPtr srsp(new GSTSRSRef(
				boost::static_pointer_cast<GSTSRSRef>(srs)->getID()));
			ar &boost::serialization::make_nvp("srsp", srsp);
		}
		else
		{
			ar &boost::serialization::make_nvp("srsp", srs);
		}
	}
	else
	{
		// is loading
		ar &boost::serialization::make_nvp("srsp", srs);
	}

	ar &BOOST_SERIALIZATION_NVP(various_properties);
	if(version >= 3)
	{
		// output authority and code, e.g. EPSG:31469, if the SRS has the
		// information
		//
		// note: only extra information on saving, this is discarded on loading
		std::string srsItemDesc;
		if(Archive::is_saving::value)
		{
			auto srsItem = dynamic_cast<const SRSItemDesc *>(srs.get());
			if(srsItem)
			{
				srsItemDesc = srsItem->code_type + ":" + srsItem->code_value;
			}
		}
		ar &boost::serialization::make_nvp("srs", srsItemDesc);
	}
}

//-----------------------------------------------------------------------------------------------------------#

struct GST_API_EXPORT SessionArchive
{
	SessionArchive()
	{
	}

	std::vector<ObjArchivePtr> objectArchives;

	/// to file
	static void ToFile(boost::shared_ptr<SessionArchive> sarchive,
					   const std::string &filename);
	static boost::shared_ptr<SessionArchive> FromFile(
		const std::string &filename,
		bool throwIfLinkedFilesAreNotExistent = true);

	/// boost serialization access
	template<typename Archive>
	void serialize(Archive &ar, const unsigned int version);
};
typedef boost::shared_ptr<SessionArchive> SessionArchivePtr;

template<typename Archive>
void SessionArchive::serialize(Archive &ar, const unsigned int version)
{
	ar &boost::serialization::make_nvp("objectArchives", this->objectArchives);
}

} // namespace Geometry
} // namespace GST

BOOST_CLASS_EXPORT_KEY(GST::Geometry::ObjectArchive);
BOOST_CLASS_EXPORT_KEY(GST::Geometry::SessionArchive);

BOOST_CLASS_VERSION(GST::Geometry::ObjectArchive, 3)
BOOST_CLASS_VERSION(GST::Geometry::SessionArchive, 1)

#endif //_OBJECT_ARCHIVE_H_
