#if !defined(__OBJUTILS_HPP__)
#define __OBJUTILS_HPP__
#include <objects/general/general__.hpp>
#include <objects/seqloc/seqloc__.hpp>
#include <serial/objistr.hpp>
#include <serial/objistrasn.hpp>
#include <serial/objistrasnb.hpp>
#include <serial/objistrjson.hpp>
#include <serial/objistrxml.hpp>
#include <serial/objostr.hpp>
#include <serial/objostrasn.hpp>
#include <serial/objostrasnb.hpp>
#include <serial/objostrjson.hpp>
#include <serial/objostrxml.hpp>
#include <serial/objhook.hpp>
#include <serial/serial.hpp>

/***********************************************************************************************************************
//	this is to convert e_Id variant in object id into e_Str variant so that Cn3D 4.1- can work correctly
************************************************************************************************************************/
class CObjectIdWriteHooker: public ncbi::CWriteChoiceVariantHook
{
	virtual void WriteChoiceVariant(ncbi::CObjectOStream& os, const ncbi::CConstObjectInfoCV& variant);   
};

ncbi::CObjectOStream * CreateObjOStream(ncbi::CNcbiOstream& os, ncbi::ESerialDataFormat eFormat = ncbi::eSerial_AsnText, ncbi::TSerial_Format_Flags fFormatFlags = 0, bool numeric_user_id_to_string = true);
ncbi::CObjectIStream * CreateObjIStream(ncbi::CNcbiIstream& is, ncbi::ESerialDataFormat eFormat = ncbi::eSerial_AsnText);



template<class BioObj> 
void ObjStreamOut(ncbi::CNcbiOstream& os, const BioObj& rBioObj, ncbi::ESerialDataFormat eFormat = ncbi::eSerial_AsnText, ncbi::TSerial_Format_Flags fFormatFlags = 0, bool numeric_user_id_to_string = true)
{
	ncbi::CObjectOStream *pOStream = CreateObjOStream(os, eFormat, fFormatFlags, numeric_user_id_to_string);
	/////ncbi::CObjectOStream *pOStream = ncbi::CObjectOStream::Open(eFormat, os, eNoOwnership, fFormatFlags);
	/////
	/////if (ncbi::eSerial_Xml == eFormat)	//Get rid of dtd
	/////{
	/////	ncbi::CObjectOStreamXml *p_os_xml = dynamic_cast< ncbi::CObjectOStreamXml* > (pOStream);
	/////	if (nullptr != p_os_xml)
	/////		p_os_xml->SetReferenceDTD(false);
	/////}
	/////
	/////if (numeric_user_id_to_string)
	/////	ncbi::CObjectTypeInfo(ncbi::objects::CSeq_id::GetTypeInfo()).FindVariant("local").SetLocalWriteHook(*pOStream, new CObjectIdWriteHooker);
	
	
	*pOStream << rBioObj;
	delete pOStream;
}

template<class BioObj> 
void ObjStreamOut(ncbi::CNcbiOstream& os, const BioObj* pBioObj, ncbi::ESerialDataFormat eFormat = ncbi::eSerial_AsnText, ncbi::TSerial_Format_Flags fFormatFlags = 0, bool numeric_user_id_to_string = true)
{
	if (nullptr == pBioObj) return;
	
	ncbi::CObjectOStream *pOStream = CreateObjOStream(os, eFormat, fFormatFlags, numeric_user_id_to_string);
	
	/////ncbi::CObjectOStream *pOStream = ncbi::CObjectOStream::Open(eFormat, os, eNoOwnership, fFormatFlags);
	/////
	/////if (ncbi::eSerial_Xml == eFormat)	//Get rid of dtd
	/////{
	/////	ncbi::CObjectOStreamXml *p_os_xml = dynamic_cast< ncbi::CObjectOStreamXml* > (pOStream);
	/////	if (nullptr != p_os_xml)
	/////		p_os_xml->SetReferenceDTD(false);
	/////}
	/////if (numeric_user_id_to_string)
	/////	ncbi::CObjectTypeInfo(ncbi::objects::CSeq_id::GetTypeInfo()).FindVariant("local").SetLocalWriteHook(*pOStream, new CObjectIdWriteHooker);
	*pOStream << (*pBioObj);
	delete pOStream;
}



template<class BioObj> 
void ObjStreamIn(ncbi::CNcbiIstream& is, BioObj& rBioObj, ncbi::ESerialDataFormat eFormat = ncbi::eSerial_AsnText)
{
	
	ncbi::CObjectIStream *pIStream = CreateObjIStream(is, eFormat);

	*pIStream >> rBioObj;
	delete pIStream;
}

template<class BioObj> 
BioObj* ObjStreamIn(ncbi::CNcbiIstream& is, BioObj* pBioObj = nullptr, ncbi::ESerialDataFormat eFormat = ncbi::eSerial_AsnText)
{
	BioObj* pEffective = pBioObj ? pBioObj : new BioObj();
	ncbi::CObjectIStream *pIStream = CreateObjIStream(is, eFormat);

	*pIStream >> (*pEffective);
	delete pIStream;
	return pEffective;
}

template<class BioObj>
std::string GetString(const BioObj& rBioObj)
{
	std::stringstream ss;
	ObjStreamOut<BioObj> (ss, rBioObj);
	return ss.str();
}



#endif
