/*
 * EdgeTechHandler.h
 *
 *  Created on: Oct 30, 2012
 *      Author: ericjmartin
 */

#ifndef EDGETECHHANDLER_H_
#define EDGETECHHANDLER_H_

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <math.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/select.h>
#include <sys/time.h>


#include "EdgeTechMessage.h"
#include "EdgeTechSubsystem.h"
#include "EdgeTechHeaders.h"

#define ET_SUBSYSTEMS 3
#define MAX_NETCMDLEN 4096
#define POLL_TIME_MILLISECONDS 200
#define POLL_RETRY_MAX 1

#ifdef _QNX
typedef unsigned long useconds_t;
typedef long suseconds_t;
#endif

long minimum(long a, long b);
static void mul64(unsigned long a, unsigned long b, unsigned long *prh, unsigned long *prl);
static void add32to64(unsigned long a, unsigned long *prh, unsigned long *prl);

class EdgeTechHandler {
public:

	enum EPORTTYPE {
		PORT_CMD, PORT_DATA
	};
	enum ESHUTDOWNTYPE {
		shutdownTypeSonarProgram = 0, shutdownTypeOSShutdown, shutdownTypeOSReboot
	};

	enum ETRIGGERMODE {
		triggerModeInternal = 0, triggerModeExternal, triggerModeCoupled, triggerModeGated
	};
//
//	Constructor/Destructor services
//
	EdgeTechHandler(char * sonarSockIP, int sonarCmdSockPort, int sonarDataSockPort, FILE * logfds = stdout);
	virtual ~EdgeTechHandler();
	bool Connect();

	void Disconnect();
	bool isConnected();

	bool Initialize();
//
//	Print Services
//

	void printStatus(FILE * fid);

//
//	Query Services
//

	int QueryCommonSettings(const long &lTimeOutMS = POLL_TIME_MILLISECONDS);
	int QueryPulseFileListQuery(subsysId_t subsys, const long &lTimeOutMS = POLL_TIME_MILLISECONDS);
	int PingOnce(subsysId_t subsys, const long &lTimeOutMS = POLL_TIME_MILLISECONDS);
	bool IsHealthy(const long &lTimeOutMS = POLL_TIME_MILLISECONDS);
//
//	Enabling Services
//
	int EnablePing(subsysId_t subsys, bool bEnable, const bool &bUpdate, const long &lTimeOutMS = POLL_TIME_MILLISECONDS);
	int EnableStorage(bool bEnable, const bool &bUpdate, const long &lTimeOutMS = POLL_TIME_MILLISECONDS);
	int EnableAGC(bool bEnable, const bool &bUpdate, const long &lTimeOutMS = POLL_TIME_MILLISECONDS);
	bool isAGCEnabled(void);

	int EnablePingAllChannels(bool bEnable, const bool &bUpdate, const long &lTimeOutMS = POLL_TIME_MILLISECONDS);

//
// Configuration Services
//
	int SetPulseFile(subsysId_t subsys, const char * sPulsefilename, int len, const bool &bUpdate, const long &lTimeOutMS = POLL_TIME_MILLISECONDS);
	int SetRxGain(const float &iRxGain, const bool &bUpdate, const long &lTimeOutMS = POLL_TIME_MILLISECONDS);
	int SetTxPower(subsysId_t subsys, const float &rfTxPower, const bool &bUpdate, const long &lTimeOutMS = POLL_TIME_MILLISECONDS);
	int SetRange(subsysId_t subsys, const float &fRangeM, const bool &bUpdate, const long &lTimeOutMS = POLL_TIME_MILLISECONDS);
	int SetTriggerMode(subsysId_t subsys, ETRIGGERMODE trigMode, const bool &bUpdate, const long &lTimeOutMS = POLL_TIME_MILLISECONDS);
	int SetTimeFromSystem(const bool &bUpdate, const long &lTimeOutMS = POLL_TIME_MILLISECONDS);
	int SetPingRate(subsysId_t subsys, const float &fPingRatePPS, const bool &bUpdate, const long &lTimeOutMS = POLL_TIME_MILLISECONDS);
	int SetPulseDuration(subsysId_t subsys, const float &rfPingDuration, const bool &bUpdate, const long &lTimeOutMS = POLL_TIME_MILLISECONDS);


//
//	Data Transmission Services
//

	int SendAltitudeData(const long &flags, const float &altitudeM, const float &forwardVelocityMS, const float &crossTrackVelocityMS, const long &lTimeOutMS = POLL_TIME_MILLISECONDS);

	int SendPressureData(const float &pressurePSI, const float &tempC, float const &salPSU, const float &condSM, const float &sosMS, const float &depthM, const long &flags, const long &lTimeOutMS = POLL_TIME_MILLISECONDS);

	int SendCompositeSituation(const long &flags, const unsigned char &vDirections, const ulonglong &timestampNS, const double &latitudeD, const double &longitudeD, const float &depthM, const float &altitudeM, const float &heaveM, const float &velocity1MS, const float &velocity2MS,
			const float &velocityDownMS, const float &pitchD, const float &rollD, const float &headingD, const float &soundSpeedMS, const float &waterTempC, const long &lTimeOutMS = POLL_TIME_MILLISECONDS);

	int SendSituation(const long &flags, const ulonglong &timestampmicroS, const double &latitudeD, const double &longitudeD, const double &depthM, const double &headingD, const double &pitchD, const double &rollD, const double &xRelativePosM, const double &yRelativePosM, const double &zRelativePosM,
			const double &xVelocityMS, const double &yVelocityMS, const double &zVelocityMS, const double &northVelocityMS, const double &eastVelocityMS, const double &downVelocityMS, const double &xAngularRateDS, const double &yAngularRateDS, const double &zAngularRateDS,
			const double &xAccelerationMS, const double &yAccelerationMS, const double &zAccelerationMS, const double &latitudeStandardDeviationM, const double &longitudeStandardDeviationM, const double &depthStandardDeviationM, const double &headingStandardDeviationD,
			const double &pitchStandardDeviationD, const double &rollStandardDeviationD, const long &lTimeOutMS = POLL_TIME_MILLISECONDS);

//
//	Message Handling Services
//
	bool SendCommand(unsigned short unMessage, unsigned char ucCommand = SONAR_COMMAND_GET, unsigned char subsys = SUBSYSID_SB, unsigned char ucChannel = 0, unsigned char *pbyMessage = NULL, unsigned long ulBytesInMessage = 0, const long &lTimeOutMS = POLL_TIME_MILLISECONDS);

	bool ReceiveMessage(const long &lTimeOutMS = POLL_TIME_MILLISECONDS);

protected:

	bool HandleSonarCommand(const EdgeTechMessage &rMessage);
	void HandleSonarError(const EdgeTechMessage &rMessage);
	int GetSubsysIdxFromMessage(const EdgeTechMessage &rMessage);


int EdgeTechHandler::TimetoMicroseconds(ulonglong* timestampus, timespec * ts = NULL);
int EdgeTechHandler::TimetoNanoseconds(ulonglong* timestampns, timespec * ts = NULL );
//	void SetTriggerMode(const long &rlTriggerMode);

//	void SetTriggerModeProperties(const long &rlTriggerMode,
//			long lDelayInMicroseconds, long lCoupledSubsystemIndex,
//			long lEventsToTriggerOn);

//	void EnablePingDataTxOnSonarChannel(const bool &rbEnable);

//	bool HandleSonarData(const EdgeTechMessage &rMessage,
//			const unsigned long &rulTimeStamp);

	bool SendMessage(EdgeTechMessage &rMessage, EPORTTYPE port, const long &lTimeOutMS = POLL_TIME_MILLISECONDS);



private:

	FILE * logfds;
	char c_sockAddress[32];
	int c_cmdSockPort, c_dataSockPort, c_cmdSockfd, c_dataSockfd;

	//pollfd c_ufds[2];
	fd_set c_readfds;

	bool c_netCmdConnected;
	bool c_netDataConnected;

	bool c_bMasterRecordEnabled;
	bool c_bStorageMessageDataEnabled;
	bool c_bDiskLoggingEnabled;
	char c_cCurrentLogFileName[128];
	long c_lDiskLogFreeSpace;
	long c_lCurrentLogFileSize;

	char c_cSystemVersion[ulMaxVersionStringLength_c];

	long c_lServerSecs;
	long c_lServerMillisecs;
	long c_lNetTimeOutMs;

	EdgeTechSubsystem etsubsys[ET_SUBSYSTEMS];

//	static bool m_bIdTableLoaded;
//	static bool m_bAutoShutdownOS;
//	static int m_iRefCount;

	unsigned long m_ulMaxPulseFiles;
	unsigned long m_ulMaxFishTypes;

};



#endif /* EDGETECHHANDLER_H_ */
