#pragma once

#include <cstdint>
#include <QSerialPort>
#include <QByteArray>
#include <QTimer>

struct OE_document;

class Machine : public QObject
{
	Q_OBJECT
	enum class Command : uint8_t
	{
		kAddPoints = 0,
		kDeletePoints,
		kStopMove,
		kStartMove,
		kSetParam,
		kGotoXY,
		kMovedXdY,
		kGotoNextPoint,
		kSetNPoint,
		kSetPos,
	};
public:
#pragma pack(push, 1)
	struct SlaveInfo
	{
		uint8_t  sequence;
		uint16_t status;
		uint16_t spaceSize;
		uint16_t freeSpace;
		int16_t  posX;
		int16_t  posY;
		uint16_t nPoint;
	};
#pragma pack(pop)
	Machine(unsigned msTimeout, unsigned retries);
	void connectPort(QString portname=QString());
	void disconnectPort();
	virtual ~Machine();
public slots:
signals:
    void stateChanged(Machine::SlaveInfo info);
	void connectionChanged(bool connected);
public:
	bool ack();
	void deletePoints();
	void stopMove();
	void startMove();
	void setParam();
	void gotoXY(int16_t x, int16_t y);
	void movedXdY(int16_t dx, int16_t dy);
	void gotoNextPoint();
	void setNPoint(uint16_t nPoint);
	void setPos(int16_t x, int16_t y);
	void loadpoints(OE_document* document);
private:
	void handleReadyRead();
	void handleError(QSerialPort::SerialPortError serialPortError);
	void handleAliveTimeout();
	void sendCommand(Command cmd, uint8_t len=1);
	void onMsg(uint8_t* buffer);
public:
	SlaveInfo info;
private:
	QSerialPort serial;
	QTimer timerAlive;
	QString portName;
	bool connected;
	uint8_t sequence;
	uint8_t sequenceAck;
	QByteArray msgBuffer;
	QByteArray cmdBuffer;
	unsigned msTimeout;
	unsigned retries;
};
