/***************************************************************************
 Copyright (c) 2009 S Roderick <xxxstephen AT theptrgroupxxx DOT comxxx>
                               (remove the x's above)
 ***************************************************************************/
#include "BoostTypesC.h"
#include <rtt/corba/CorbaConversion.hpp>
#include <boost/date_time/posix_time/posix_time_types.hpp>  // no I/O

// must be in RTT namespace to match some rtt/corba code
namespace RTT
{

template<>
struct AnyConversion< boost::posix_time::time_duration >
{
	// define the Corba and standard (ie non-Corba) types we are using
	typedef Corba::time_duration                CorbaType;
	typedef boost::posix_time::time_duration    StdType;

	// convert CorbaType to StdTypes
	static void convert(const CorbaType& orig, StdType& ret)
	{
		ret = boost::posix_time::time_duration(orig.hours,
											   orig.minutes,
											   orig.seconds,
											   // \todo deal with microsecs vs nanosecs in local boost config
											   orig.nanoseconds);
	}

	// convert StdType to CorbaTypes
	static void convert(const StdType& orig, CorbaType& ret)
	{
		ret.hours       = orig.hours();
		ret.minutes     = orig.minutes();
		ret.seconds     = orig.seconds();
		// \todo deal with microsecs vs nanosecs in local boost config
		ret.nanoseconds = orig.fractional_seconds();
	}

	static CorbaType* toAny(const StdType& orig) {
		Logger::In in("BoostCorbaConversion");
//            log(Debug)<< "Converting type 'LogMessage' to Corba::LogMessage." <<endlog();
		CorbaType* ret = new CorbaType();
		convert(orig, *ret);
		return ret;
	}

	static StdType get(const CorbaType* orig) {
		Logger::In in("BoostCorbaConversion");
//            log(Debug)<< "Converting type Corba::LogMessage to 'LogMessage'" <<endlog();

		StdType ret;
		convert(*orig, ret);
		return ret;
	}

	static bool update(const CORBA::Any& any, StdType& ret) {
		Logger::In in("BoostCorbaConversion");
//            log(Debug)<< "Updating LogMessage from Corba::Any " << endlog();
		CorbaType* orig;
		if ( any >>= orig )
		{
			convert(*orig, ret);
			return true;
		}
		return false;
	}

	static CORBA::Any_ptr createAny( const StdType& t ) {
		Logger::In in("BoostCorbaConversion");
//            log(Debug)<< "Creating Corba::Any type for 'LogMessage'" <<endlog();
		CORBA::Any_ptr ret = new CORBA::Any();
		*ret <<= toAny( t );
		return ret;
	}
};

/*
   It seems that the boost library does *NOT* allow you to get at the
   underlying representation of a ptime object. So we can't just get the
   64- or 96-bits and package them ourselves. This was the compromise,
   also given the limited number of ptime contstructors.

   If you find another way .... please let me know ... S Roderick
*/
template<>
struct AnyConversion< boost::posix_time::ptime >
{
	typedef Corba::ptime                CorbaType;
	typedef boost::posix_time::ptime    StdType;

	// convert CorbaType to StdType
	static void convert(const CorbaType& orig, StdType& ret)
	{
		// see next convert() for details of "-1"
		if (-1 == orig.date)
		{
			ret = StdType(boost::posix_time::not_a_date_time);
		}
		else
		{
			// julian day
			boost::gregorian::date      date(
				(boost::gregorian::date::date_int_type)orig.date);
			boost::posix_time::time_duration    tod;
			AnyConversion<boost::posix_time::time_duration>::convert(
				orig.time_of_day, tod);
			ret = StdType(date, tod);
		}
	}

	// convert StdType to CorbaType
	static void convert(const StdType& orig, CorbaType& ret)
	{
		// must special case handle is_special(), else conversion of date
		// throws boost::gregorian::bad_year for invalid year
		if (orig.is_special())
		{
			// presume not-a-date-time
			// \todo deal with other "special values"
			ret.date = -1;
//                log(Error) << "special date " << ret.date << endlog();
		}
		else
		{
			ret.date        = orig.date().julian_day();
//                log(Error) << "ptime to Corba: date " << ret.date << endlog();
			boost::posix_time::time_duration    tod = orig.time_of_day();
			AnyConversion<boost::posix_time::time_duration>::convert(
				tod, ret.time_of_day);
		}
	}

	static CorbaType* toAny(const StdType& orig) {
		Logger::In in("BoostCorbaConversion");
//            log(Debug)<< "Converting type 'boost_ptime' to Corba::boost_ptime." <<endlog();
		CorbaType* ret = new CorbaType();
//            log(Error) << "orig " << orig.date << endlog();
		convert(orig, *ret);
		return ret;
	}

	static StdType get(const CorbaType* orig) {
		Logger::In in("BoostCorbaConversion");
//            log(Debug)<< "Converting type Corba::boost_ptime to 'boost_ptime'" <<endlog();

		StdType ret;
		convert(*orig, ret);
		return ret;
	}

	static bool update(const CORBA::Any& any, StdType& ret) {
		Logger::In in("BoostCorbaConversion");
//            log(Debug)<< "Updating boost_ptime from Corba::Any " << endlog();
		CorbaType* orig;
		if ( any >>= orig )
		{
			convert(*orig, ret);
			return true;
		}
		return false;
	}

	static CORBA::Any_ptr createAny( const StdType& t ) {
		Logger::In in("BoostCorbaConversion");
//            log(Debug)<< "Creating Corba::Any type for 'boost_ptime'" <<endlog();
		CORBA::Any_ptr ret = new CORBA::Any();
		*ret <<= toAny( t );
		return ret;
	}
};

// namespace
};



