////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
// All Rights Reserved.
// Confidential and Proprietary - Qualcomm Technologies, Inc.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// THIS IS AUTO-GENERATED CODE.  PLEASE DO NOT EDIT (File bug reports against tools).
///
/// Auto-generated by: Parameter Parser V5.5.1 (2411131018)
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @file  parametereztunecom.h
/// @brief Auto-generated Chromatix parameter file
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#ifndef PARAMETEREZTUNECOM_H
#define PARAMETEREZTUNECOM_H

#ifdef _WIN32

#undef UNICODE
#define _WINSOCKAPI_

#include <windows.h>
#include <winsock2.h>
#include <Ws2tcpip.h>

typedef int SOCKET_LEN;

#define PARAMETER_INVALID_SOCKET INVALID_SOCKET

// Need to link with Ws2_32.lib
#pragma comment (lib, "Ws2_32.lib")

#else

#include <cstdio>
#include <cstdlib>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <poll.h>

// Supress warning: swab.h:104:29: error: unused function '__swab32s' [-Werror,-Wunused-function]
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-function"
#include <netinet/in.h>
#pragma GCC diagnostic pop

typedef socklen_t SOCKET_LEN;

#define PARAMETER_INVALID_SOCKET -1

#endif // _WIN32

#include <atomic>
#include <condition_variable>
#include <thread>
#include <queue>
#include <chrono>
#include <mutex>

#include "parameterutils.h"
#include "parametertypes.h"
#include "parametereztunecombase.h"

#define SUN_UNIX_PATH_NAME "#EzTuneServer"
#define SUN_UNIX_PATH_MAX 108

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// ParameterEzTuneCom
///
/// @brief Ez Tune Worker
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class ParameterEzTuneCom : public ParameterEzTuneComBase
{
public:
    struct sockaddr_un_t
    {
        uint16_t sun_family;                  /* AF_UNIX */
        char     sun_path[SUN_UNIX_PATH_MAX]; /* pathname */
    };

    class SocketAddress
    {
    public:
        enum class AddrType
        {
            External,
            Internal
        };

        SocketAddress()
        {
            PARAMETER_INITIALIZE(Address.Sun);
            PARAMETER_INITIALIZE(Address.Sin);
            Type   = AddrType::External;
            Length = sizeof(struct sockaddr_in);
            SetupSocket(AddrType::External, ExternalPort);
        }

        union SockAddr
        {
            struct sockaddr_un_t Sun;
            struct sockaddr_in   Sin;
        } Address;

        void SetupSocket(AddrType type, UINT16 port);

        PARAMETER_INLINE void IncrementPort()
        {
            SetupSocket(Type, Port + 1);
        }

        AddrType  Type;
        socklen_t Length;
        UINT16    Port;
        CHAR      PortName[SUN_UNIX_PATH_MAX];
    };

    class SocketID
    {
    public:
        PARAMETER_INLINE SocketID()
        {
            LogAPI = nullptr;
            Initialize();
        }

        PARAMETER_INLINE SocketID(IParameterLoggingAPI* logAPI)
        {
            LogAPI = logAPI;
            Initialize();
        }

        PARAMETER_INLINE bool IsOpen()
        {
            return ID != PARAMETER_INVALID_SOCKET;
        }

        PARAMETER_INLINE bool IsConnected()
        {
            return Connection != PARAMETER_INVALID_SOCKET;
        }

        PARAMETER_INLINE void Initialize()
        {
            ID         = PARAMETER_INVALID_SOCKET;
            Connection = PARAMETER_INVALID_SOCKET;
            PARAMETER_INITIALIZE(SocketAddr);
            PARAMETER_INITIALIZE(ConnectAddr);
        }

        void CloseSocket();
        void CloseConnection();

        INT32 ReadData(
            BYTE*  packet,
            UINT32 packetSize,
            INT32  timeout,
            bool&  exit);

        INT32 WriteData(
            BYTE*  packet,
            UINT32 packetSize);

        SocketAddress SocketAddr;
        SocketAddress ConnectAddr;

#ifdef _WIN32
        SOCKET ID;
        SOCKET Connection;
#else
        INT32 ID;
        INT32 Connection;
#endif

        IParameterLoggingAPI* LogAPI;
    };

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// ParameterEzTuneCom
    /// @brief Constructor
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ParameterEzTuneCom(IParameterLoggingAPI* logAPI);

    PARAMETER_INLINE static INT32 GetError()
    {
#ifdef _WIN32
        return WSAGetLastError();
#else
        return errno;
#endif
    }

    static bool UseInternalPort;

protected:
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// StartCom
    /// @brief Starts the Ez Tune com server
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    virtual void StartCom();

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// StopEzSpectraTune
    /// @brief Stops the Ez Tune com server
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    virtual void StopCom();

    virtual INT32 ReadData(
        BYTE*  packet,
        UINT32 packetSize,
        INT32  timeout,
        bool& exit);

    virtual INT32 WriteData(
        BYTE*  packet,
        UINT32 packetSize);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// OpenPort
    ///
    /// @brief Open a TCPIP port
    ///
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    UINT16 OpenPort();

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// ClosePort
    ///
    /// @brief Close a TCPIP port
    ///
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    void ClosePort();

    bool InitSockets();

    void CloseSocket(
        SocketID& sockID,
        bool term);

    void CloseConnection(
        SocketID& sockID);

    void LogDebug(const CHAR* message, const SocketID& socket, const CHAR* portName, INT32 result, INT32 error);
    void LogError(const CHAR* message, const SocketID& socket, const CHAR* portName, INT32 result, INT32 error);

    bool      m_initSockets;
    SocketID  m_dataID;
};

#endif
