/*
 * Copyright (C) 2012-2026 MotionSystems
 *
 * This file is part of ForceSeatMI SDK.
 *
 * www.motionsystems.eu
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
 * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
#pragma once

#include <array>
#include "ForceSeatMI_Functions.h"

/*
 * This is simple helper class that allows to control the motion platform the same way as CNC machines are controlled:
 * - GoToSync           - you can issue GoTo command with specified destination position, velocity and acceleration
 * - GetCurrentPosition - you can check current top table position
 * - KeepAliveFor       - you can delay the program execution (sleep) and at the same time prevent the inactivity mechanism in ForceSeatPM to be triggered
 */
class ForceSeatMI_GoToAPI
{
	public:
		struct Position
		{
			bool valid;

			float roll;  // in radians, roll  < 0 = left,  roll > 0  = right
			float pitch; // in radians, pitch < 0 = front, pitch > 0 = rear
			float yaw;   // in radians, yaw   < 0 = right, yaw > 0   = left
			float heave; // in mm, heave < 0 - down, heave > 0 - top
			float sway;  // in mm, sway  < 0 - left, sway  > 0 - right
			float surge; // in mm, surge < 0 - rear, surge > 0 - front
		};

		explicit ForceSeatMI_GoToAPI(const char* profileName);
		~ForceSeatMI_GoToAPI();

		// Park the motion platform. It ends when parking position is reached or when 15 seconds timeout occurs.
		void ParkSync();

		// Move the motion platform to center position. It ends when parking position is reached or when 15 seconds timeout occurs.
		void CenterSync();

		// Go to specified position with specified velocity and acceleration.
		// 1. Function blocks until the final position is send to the motion platform.
		// 2. This function does not use any feedback, it just calculates trajecotory and
		//    send intermediate positions to ForceSeatPM.
		// 3. If trajectory is longer then 15 seconds, the function will stop after 15 seconds.
		void GoToSync(double roll,  double rollVel,  double rollAcc,
					  double pitch, double pitchVel, double pitchAcc,
					  double yaw,   double yawVel,   double yawAcc,
					  double heave, double heaveVel, double heaveAcc,
					  double sway,  double swayVel,  double swayAcc,
					  double surge, double surgeVel, double surgeAcc);

		// It stops the program execution for specified amount of the time but at the same time it prevents 
		// ForceSeatPM from detecting inactivity.
		void KeepAliveFor(unsigned int duration_ms);

		// Get current motion platform position (top table position)
		Position GetCurrentPosition() const;

	private:
		FSMI_Handle m_api { nullptr };

		enum MotionId
		{
			Roll,
			Pitch,
			Yaw,
			Heave,
			Sway,
			Surge,

			__Count,
			__First = Roll
		};

		std::array<double, MotionId::__Count> m_recentReqPos {};

		ForceSeatMI_GoToAPI(const ForceSeatMI_GoToAPI &)             = delete;
		ForceSeatMI_GoToAPI(const ForceSeatMI_GoToAPI &&)            = delete;
		ForceSeatMI_GoToAPI& operator=(const ForceSeatMI_GoToAPI &)  = delete;
		ForceSeatMI_GoToAPI& operator=(const ForceSeatMI_GoToAPI &&) = delete;

		void Read(FSMI_PlatformInfo& info) const;
};

