#include <iostream>
#include <string>
#include <fstream>
#include <stdexcept>
#include <boost/serialization/base_object.hpp>
#include <boost/archive/xml_oarchive.hpp>
#include <boost/archive/xml_iarchive.hpp>
#include <boost/serialization/export.hpp>


class A 
{
	friend class boost::serialization::access;
	
	private:
		template<class Archive>
	    void serialize(Archive & ar, const unsigned int version)
	    {
	    	ar & BOOST_SERIALIZATION_NVP(text);
	    	ar & BOOST_SERIALIZATION_NVP(var);
	    }
		
	protected:
		std::string text;
		int var;
	
	public:
		A() : text("Class A")
		{}
		
		A(int vara) : text("Class A"), var(vara)
		{}
		
		virtual ~A()
		{}
		
		std::string Text()
		{
			return this->text;
		}
		
		int Var()
		{
			return this->var;
		}
};

BOOST_IS_ABSTRACT(A);

class B : public A
{
	friend class boost::serialization::access;
	
	private:
		template<class Archive>
	    void serialize(Archive & ar, const unsigned int version)
	    {
	    	ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(A);
	    	ar & BOOST_SERIALIZATION_NVP(add);
	    }
	    
	protected:
		std::string add;
	public:
		B()
		{
			text = "Class B";
			add = "addVara";
		}
		
		B(int vara)
		{
			text = "Class B";
			add = "addVara";
			var = vara;
		}
		std::string Add()
		{
			return this->add;
		}
		virtual ~B()
		{}
		
};

BOOST_CLASS_EXPORT(A)
BOOST_CLASS_EXPORT(B)

void output(A* aClass)
{
	std::cout <<  "Text: " << aClass->Text() << " Var: " << aClass->Var() << std::endl;
}

void save(A* aClass)
{
	try
	{
		std::ofstream ofs("serial.txt");
		boost::archive::xml_oarchive oa(ofs);
		
		output(aClass);
		oa << BOOST_SERIALIZATION_NVP(aClass);
	}
	catch(std::exception* ex)
	{
		std::cout << "Save" << std::endl;
		std::cout << ex->what() << std::endl;
	}
}

A* load()
{
	try
	{
		A* aClass;
		std::ifstream ifs("serial.txt");
		boost::archive::xml_iarchive ia(ifs);
		
		ia >> BOOST_SERIALIZATION_NVP(aClass);
		output(aClass);
		return aClass;
	}
	catch(std::exception* ex)
	{
		std::cout << "Load" << std::endl;
		std::cout << ex->what() << std::endl;
	}
}

int main(int argc, char** argv)
{
	A* aClass = new B(5);
	A* aClass2;

	output(aClass);
	std::cout << "saving" << std::endl;
	save(aClass);
	std::cout << "saved" << std::endl;
	
	std::cout << "loading" << std::endl;
	aClass2 = load();
	std::cout << "loaded" << std::endl;
	output(aClass2);
	
	std::cout << "dynamic cast" << std::endl;
	B* bClass = dynamic_cast<B*>(aClass2);
	output(bClass);
	

	return 0;	
}

