/*
   HARK Library
   Copyright (C) 2021 Honda Research Institute Japan Inc.
 */

#if !defined(_HARKLIB_SOURCE_H_INCLUDED_)
#define _HARKLIB_SOURCE_H_INCLUDED_ 1

#include "hark-lib/hark-lib.h"
#include "hark-lib/object.h"

namespace hark
{
    class Source: public object
    {
    public:
        enum TFDim {
            TFHeight,
            TFDirection,
            TFRange
        };
        enum CompareMode {
            DEG,
            TFINDEX
        };

    public:
        Source();
        Source(const Source &src);

    public:
        int tfindexDistance(const int *y) const;
        int tfindexDistance(const Source &src) const;

        float angle(const float *y) const;
        float angle(const Source &src) const;

        // virtual ObjectRef clone();
        // virtual void printOn(std::ostream &out) const;
        // void readFrom(std::istream &in);

        virtual std::ostream& write(std::ostream &os) const;

    public:
        float x[3];
        float power;
        int id;
        int sub_id;
        int mic_id;
        float remaining;
        int count;
        int first_found_count;
        int last_found_count;

        int tfindex[3];
        int tfindex_max[3];
        int tfindex_min[3];
        CompareMode compare_mode;

    };

    // Structures for socket communication.
    // I'm specifiying a minimum alignment with alignas(1) based on the C++11 specification,
    // but sizeof(hark::SourceInfo_s) returns as incorrect value of 32 instead of 28.
    // There seems to be 4 bytes of padding after the elevation valiable.
    // If specified by pragma pack, it depends on the compiler, so for general-purpose
    // implementation, the side that uses the structure should perform a procedure that
    // does not depend on alignment.
    /*
    struct alignas(1) SourceInfo_s
    {
        alignas(1) int32_t source_id;
        alignas(1) float azimuth;
        alignas(1) float elevation;
        alignas(1) int64_t tv_sec;
        alignas(1) int64_t tv_usec;
    };
    struct alignas(1) UtteranceInfo_s
    {
        alignas(1) int64_t client_id;
        alignas(1) int32_t mic_index;
        alignas(1) int32_t source_id;
        alignas(1) int32_t sub_id;
        alignas(1) float azimuth;
        alignas(1) float elevation;
        alignas(1) int64_t tv_sec;
        alignas(1) int64_t tv_usec;
    };
    */

    // Note that this class is unnecessarily padded when used for socket communication.
    class SourceInfo: public object
    {
    public:
        SourceInfo();
        SourceInfo(const SourceInfo &src);

        virtual std::ostream& write(std::ostream &os) const;

    public:
        static constexpr int32_t size = sizeof(int32_t)
                                      + sizeof(float)
                                      + sizeof(float)
                                      + sizeof(int64_t)
                                      + sizeof(int64_t);
        int32_t source_id;
        float azimuth;
        float elevation;
        int64_t tv_sec;
        int64_t tv_usec;
    };

    class UtteranceInfo: public object
    {
    public:
        UtteranceInfo();
        UtteranceInfo(const UtteranceInfo &src);

        virtual std::ostream& write(std::ostream &os) const;

    public:
        static constexpr int32_t size = sizeof(int64_t)
                                      + sizeof(int32_t)
                                      + sizeof(int32_t)
                                      + sizeof(int32_t)
                                      + sizeof(float)
                                      + sizeof(float)
                                      + sizeof(int64_t)
                                      + sizeof(int64_t);
        int64_t client_id;
        int32_t mic_index;
        int32_t source_id;
        int32_t sub_id;
        float azimuth;
        float elevation;
        int64_t tv_sec;
        int64_t tv_usec;
    };
}

#endif /* #if !defined(_HARKLIB_SOURCE_H_INCLUDED_) */

/* end of file */
