#pragma once

#include <QObject>
#include <QAbstractSocket>
#include <QThread>
#include <QMutex>
#include <QMutexLocker>
//#include <QByteArray>
//#include <QBuffer>
#include <string>
#include <algorithm>

QT_BEGIN_NAMESPACE
class QTcpSocket;
class QNetworkSession;
class QImage;
QT_END_NAMESPACE


// for vector 3
#include "Environment.h"

#include "TrafficInfoData.h"

		enum {
			BUTTON_TEMPO_OFF=1,
			BUTTON_TEMPO_ON=2,
			BUTTON_TEMPO_CANCEL=4,
			BUTTON_TEMPO_SET=8,
			BUTTON_TEMPO_RESUME=16,
			BUTTON_TEMPO_FASTER=32,
			BUTTON_TEMPO_SLOWER=64,
			BUTTON_TEMPO_RELEASE=128,
			BUTTON_LEFT_BLINKER=256,
			BUTTON_RIGHT_BLINKER=512,
			BUTTON_VPROF0=1024,
			BUTTON_VPROF1=2048,
			BUTTON_VPROF2=4096
		};


class Client : public QObject
{
  Q_OBJECT

public:
  enum {SAVE_IMAGE=0x124DD8, SEND_IMAGE, SEND_STATUS, CALIBRATE, RESET};

  QTcpSocket *mSocket;
  QMutex mSocketMutex;
  
  std::string mHostAdress;
  int mPort;
  
  //  std::atomic<int> mConfirmCommand;
  int mConfirmCommand;

	static const int MAX_BUFFER=2048;

	int mMessageBufferIndex;
	char mMessageBuffer[MAX_BUFFER];

	// position and orientation of the driven car
	Vector3 mPosition;
	Vector3 mOrientation;
	
	float mSpeed;
	float mTargetSpeed;
	float mWheel;
	float mTargetAcceleration;
	int mButtons;
	
	int mControllerId;
	int mProfileId;
	
	TrafficInfoData mTrafficInfoData;
	
public:
  Client(const std::string hostAdress, const int port);

#define MAX_VALUE 1e6f

	void
	SendArHud(
						const bool showSpeed,
						const bool showSigns,
						const bool showAcc,
						const bool laneAssist,
						const char laneLeft,
						const char laneRight,
						const bool laneAssistVehicle,
						const char vehicleDistance,
						const bool showRoadDistanceBars,
						const bool showRoadLeftStrip,
						const bool showRoadRightStrip,
						const bool showRoadVehicleHighlight,
						const char vehicleHighlight,
						const bool showNavigation,
						const bool showRoadNavigation,
						const char heightOffset
						);
																											
private slots:
  void Disconnected();
  void ConnectHost();
  void ReadData();
  void PrintError(QAbstractSocket::SocketError socketError);

	void
	LeftBlinkerOn() {
		mButtons |= BUTTON_LEFT_BLINKER;
		SendControls(MAX_VALUE, MAX_VALUE, MAX_VALUE, 0.0f, mButtons);
	}
	void
	LeftBlinkerOff() {
		mButtons &= ~BUTTON_LEFT_BLINKER;
		SendControls(MAX_VALUE, MAX_VALUE, MAX_VALUE, 0.0f, mButtons);
	}

	void
	RightBlinkerOn() {
		mButtons |= BUTTON_RIGHT_BLINKER;
		SendControls(MAX_VALUE, MAX_VALUE, MAX_VALUE, 0.0f, mButtons);
	}
	
	void
	RightBlinkerOff() {
		mButtons &= ~BUTTON_RIGHT_BLINKER;
		SendControls(MAX_VALUE, MAX_VALUE, MAX_VALUE, 0.0f, mButtons);
	}


	void Faster() {
		mTargetAcceleration += 0.1f;
		SendControls(MAX_VALUE, 0.0f, 0.0f, mTargetAcceleration, mButtons);
	}
	void Slower() {
		mTargetAcceleration -= 0.1f;
		SendControls(MAX_VALUE, 0.0f, 0.0f, mTargetAcceleration, mButtons);
	}

	void Accelerate() {
		SendControls(MAX_VALUE, 1.0f, 0.0f, 0.0f, mButtons);
	}
	
	void Break() {
		SendControls(MAX_VALUE, 0.0f, 1.0f, 0.0f, mButtons);
	}

	void Left() {
		SendControls(-1.0f, MAX_VALUE, MAX_VALUE, 0.0f, mButtons);
	}
	
	void Right() {
		SendControls(1.0f, MAX_VALUE, MAX_VALUE, 0.0f, mButtons);
	}

	void TempoOn() {
		mTargetSpeed = mSpeed;
	}

	void ResetControls() {
		SendControls(0.0f,0.0f,0.0f, 0.0f, 0);
	}
	void TempoOff() {
		mTargetSpeed = -1.0f;
		ResetControls();
	}

	void
	//	SendControls(const float b, const float a, const float w);
	SendControls(const float wheel,
							 const float gas,
							 const float brake,
							 const float accel,
							 const int buttons);

	
	void
	UpdateTempomat();

	void
	SetControllerId(int value);

	void
	SetProfileId(int value) {
		mProfileId = value;
		SendControls(MAX_VALUE, MAX_VALUE, MAX_VALUE, MAX_VALUE, mButtons);
	}

signals:
	void Message(const QString &);
	void Speed(const float);
  void Connected();
};

