/* +------------------------------------------------------------------------+
   |                     Mobile Robot Programming Toolkit (MRPT)            |
   |                          https://www.mrpt.org/                         |
   |                                                                        |
   | Copyright (c) 2005-2022, Individual contributors, see AUTHORS file     |
   | See: https://www.mrpt.org/Authors - All rights reserved.               |
   | Released under BSD License. See: https://www.mrpt.org/License          |
   +------------------------------------------------------------------------+ */

#include "poses-precomp.h"	// Precompiled headers
//
#include <mrpt/math/TPose3D.h>
#include <mrpt/poses/CPoses3DSequence.h>
#include <mrpt/serialization/CArchive.h>

using namespace mrpt;
using namespace mrpt::poses;
using namespace mrpt::math;

IMPLEMENTS_SERIALIZABLE(CPoses3DSequence, CSerializable, mrpt::poses)

size_t CPoses3DSequence::posesCount() { return m_poses.size(); }
uint8_t CPoses3DSequence::serializeGetVersion() const { return 0; }
void CPoses3DSequence::serializeTo(mrpt::serialization::CArchive& out) const
{
	out.WriteAs<uint32_t>(m_poses.size());
	for (const auto& p : m_poses)
		out << p;
}
void CPoses3DSequence::serializeFrom(
	mrpt::serialization::CArchive& in, uint8_t version)
{
	switch (version)
	{
		case 0:
		{
			m_poses.resize(in.ReadAs<uint32_t>());
			for (auto& p : m_poses)
				in >> p;
		}
		break;
		default: MRPT_THROW_UNKNOWN_SERIALIZATION_VERSION(version);
	};
}

/*---------------------------------------------------------------
Reads the stored pose at index "ind", where the first one is 0, the last
"posesCount() - 1"
 ---------------------------------------------------------------*/
void CPoses3DSequence::getPose(unsigned int ind, CPose3D& outPose)
{
	if (ind >= m_poses.size()) THROW_EXCEPTION("getPose: Index out of range!!");

	outPose = CPose3D(m_poses[ind]);
}

/*---------------------------------------------------------------
Changes the stored pose at index "ind", where the first one is 0, the last
"posesCount() - 1"
 ---------------------------------------------------------------*/
void CPoses3DSequence::changePose(unsigned int ind, CPose3D& inPose)
{
	if (ind >= m_poses.size()) THROW_EXCEPTION("getPose: Index out of range!!");
	m_poses[ind] = inPose.asTPose();
}

/*---------------------------------------------------------------
	Appends a new pose at the end of sequence. Remember that poses are relative,
 incremental to the last one.
 ---------------------------------------------------------------*/
void CPoses3DSequence::appendPose(CPose3D& newPose)
{
	m_poses.push_back(newPose.asTPose());
}

/*---------------------------------------------------------------
			Clears the sequence.
 ---------------------------------------------------------------*/
void CPoses3DSequence::clear() { m_poses.clear(); }
/*---------------------------------------------------------------
 ---------------------------------------------------------------*/
/** Returns the absolute pose of a robot after moving "n" poses, so for "n=0"
 * the origin pose (0,0,0deg) is returned, for "n=1" the first pose is returned,
 * and for "n=posesCount()", the pose
 *  of robot after moving ALL poses is returned, all of them relative to the
 * starting pose.
 */
CPose3D CPoses3DSequence::absolutePoseOf(unsigned int n)
{
	CPose3D ret(0, 0, 0);
	unsigned int i;

	if (n > m_poses.size())
		THROW_EXCEPTION("absolutePoseOf: Index out of range!!");

	for (i = 0; i < n; i++)
		ret = ret + CPose3D(m_poses[i]);

	return ret;
}

/*---------------------------------------------------------------
	A shortcut for "absolutePoseOf( posesCount() )".
 ---------------------------------------------------------------*/
CPose3D CPoses3DSequence::absolutePoseAfterAll()
{
	return absolutePoseOf(posesCount());
}

double CPoses3DSequence::computeTraveledDistanceAfter(size_t n)
{
	double dist = 0;

	if (n > m_poses.size())
		THROW_EXCEPTION("computeTraveledDistanceAfter: Index out of range!!");

	for (size_t i = 0; i < n; i++)
		dist += m_poses[i].norm();
	return dist;
}

double CPoses3DSequence::computeTraveledDistanceAfterAll()
{
	return computeTraveledDistanceAfter(posesCount());
}
