/* +------------------------------------------------------------------------+
   |                     Mobile Robot Programming Toolkit (MRPT)            |
   |                          https://www.mrpt.org/                         |
   |                                                                        |
   | Copyright (c) 2005-2023, 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 "obs-precomp.h"  // Precompiled headers
//
#include <mrpt/obs/CObservationStereoImagesFeatures.h>
#include <mrpt/serialization/CArchive.h>

#include <fstream>

using namespace mrpt::obs;
using namespace mrpt::poses;
using namespace mrpt::math;
using namespace mrpt::img;
using namespace std;

// This must be added to any CSerializable class implementation file.
IMPLEMENTS_SERIALIZABLE(
	CObservationStereoImagesFeatures, CObservation, mrpt::obs)

CObservationStereoImagesFeatures::CObservationStereoImagesFeatures(
	const TCamera& cLeft, const TCamera& cRight, const CPose3DQuat& rCPose,
	const CPose3DQuat& cPORobot)
{
	cameraLeft = cLeft;
	cameraRight = cRight;

	rightCameraPose = rCPose;
	cameraPoseOnRobot = cPORobot;
}

void CObservationStereoImagesFeatures::saveFeaturesToTextFile(
	const std::string& filename)
{
	std::ofstream file(filename);
	ASSERT_(file.is_open());

	vector<TStereoImageFeatures>::iterator it;
	for (it = theFeatures.begin(); it != theFeatures.end(); ++it)
		file << format(
			"%u %.2f %.2f %.2f %.2f\n", it->ID, it->pixels.first.x,
			it->pixels.first.y, it->pixels.second.x, it->pixels.second.y);
}

uint8_t CObservationStereoImagesFeatures::serializeGetVersion() const
{
	return 0;
}
void CObservationStereoImagesFeatures::serializeTo(
	mrpt::serialization::CArchive& out) const
{
	// The data
	out << cameraLeft;
	out << cameraRight;
	out << rightCameraPose << cameraPoseOnRobot;
	out << (uint32_t)theFeatures.size();  // Write the number of items
	// within the feature list
	for (const auto& theFeature : theFeatures)
	{
		out << theFeature.pixels.first.x << theFeature.pixels.first.y;
		out << theFeature.pixels.second.x << theFeature.pixels.second.y;
		out << (uint32_t)theFeature.ID;
	}
	out << sensorLabel << timestamp;
}

void CObservationStereoImagesFeatures::serializeFrom(
	mrpt::serialization::CArchive& in, uint8_t version)
{
	switch (version)
	{
		case 0:
		{
			uint32_t nL, nR;
			in >> cameraLeft;
			in >> cameraRight;
			in >> rightCameraPose >> cameraPoseOnRobot;
			in >> nL;
			theFeatures.resize(nL);
			for (auto& theFeature : theFeatures)
			{
				in >> theFeature.pixels.first.x >> theFeature.pixels.first.y;
				in >> theFeature.pixels.second.x >> theFeature.pixels.second.y;
				in >> nR;
				theFeature.ID = (unsigned int)nR;
			}
			in >> sensorLabel >> timestamp;
		}
		break;
		default: MRPT_THROW_UNKNOWN_SERIALIZATION_VERSION(version);
	};
}

void CObservationStereoImagesFeatures::getDescriptionAsText(
	std::ostream& o) const
{
	CObservation::getDescriptionAsText(o);

	o << "Homogeneous matrix for the sensor's 3D pose, relative to robot "
		 "base:\n";
	o << cameraPoseOnRobot.getHomogeneousMatrixVal<CMatrixDouble44>() << "\n"
	  << cameraPoseOnRobot << "\n";

	o << "Homogeneous matrix for the RIGHT camera's 3D pose, relative to LEFT "
		 "camera reference system:\n";
	o << rightCameraPose.getHomogeneousMatrixVal<CMatrixDouble44>()
	  << rightCameraPose << endl;

	o << "Intrinsic parameters matrix for the LEFT camera:" << endl;
	CMatrixDouble33 aux = cameraLeft.intrinsicParams;
	o << aux.inMatlabFormat() << endl << aux << endl;

	o << "Distortion parameters vector for the LEFT camera:" << endl << "[ ";
	for (unsigned int i = 0; i < 5; ++i)
		o << cameraLeft.dist[i] << " ";
	o << "]" << endl;

	o << "Intrinsic parameters matrix for the RIGHT camera:" << endl;
	aux = cameraRight.intrinsicParams;
	o << aux.inMatlabFormat() << endl << aux << endl;

	o << "Distortion parameters vector for the RIGHT camera:" << endl << "[ ";
	for (unsigned int i = 0; i < 5; ++i)
		o << cameraRight.dist[i] << " ";
	o << "]" << endl;

	o << endl
	  << format(
			 " Image size: %ux%u pixels\n", (unsigned int)cameraLeft.ncols,
			 (unsigned int)cameraLeft.nrows);
	o << endl
	  << format(
			 " Number of features in images: %u\n",
			 (unsigned int)theFeatures.size());
}
