#pragma once

#include "ehs/EHS.h"
#include "ehs/Str.h"
#include "ehs/Vector.h"
#include "ehs/Array.h"
#include "ehs/DataType.h"

namespace ehs
{
	enum class AudioDeviceType
	{
		OUTPUT = 0x0,
		INPUT = 0x1,
		ALL = 0x2
	};

	enum class AudioDeviceState
	{
		ACTIVE = 0x1,
		DISABLED = 0x2,
		NOT_PRESENT = 0x4,
		UNPLUGGED = 0x8
	};

    class BaseAudioDevice
    {
	protected:
        AudioDeviceType type;
		DataType dataType;
		UInt_16 bitDepth;
		UInt_32 sampleRate;
		UInt_32 channels;
		UInt_32 period;
		UInt_32 latency;
		UInt_64 maxFrames;
		bool streaming;

    public:
        virtual ~BaseAudioDevice() = default;

        BaseAudioDevice();

        BaseAudioDevice(const BaseAudioDevice& device);

        BaseAudioDevice& operator=(const BaseAudioDevice& device);

		virtual void Release();

		virtual void OpenStream();

		virtual void CloseStream();

		virtual UInt_64 GetAvailFrames() const;

		virtual Byte* Map(UInt_64* offset, UInt_64* frames);

		virtual void UnMap(const UInt_64 offset, const UInt_64 frames);

        AudioDeviceType GetType() const;

		void SetDataType(const DataType newDataType);

		DataType GetDataType() const;

		UInt_8 GetByteDepth() const;

		UInt_16 GetBitDepth() const;

		void SetSampleRate(const UInt_32 newSampleRate);

		UInt_32 GetSampleRate() const;

		void SetChannels(const UInt_32 newChannels);

		UInt_16 GetChannels() const;

		UInt_32 GetFrameSize() const;

		void SetPeriod(const UInt_32 newPeriod);

		UInt_32 GetPeriod() const;

		void SetLatency(const UInt_32 newLatency);

		UInt_32 GetLatency() const;

		UInt_64 GetMaxFrames() const;

		bool IsStreaming() const;

		virtual bool IsValid() const;

		/// Retrieves the default audio input/output device.
		/// @param [in] type The audio device type to retrieve.
		/// @param [out] device The default audio device.
		static BaseAudioDevice GetDefault(const AudioDeviceType type);

		/// Retrieves a list of audio input/output devices.
		/// @param [in] type The audio device type to retrieve.
		/// @param [in] state The audio device state to retrieve.
		/// @param [out] devices The list of audio devices.
		static Array<BaseAudioDevice> Get(const AudioDeviceType type, const AudioDeviceState state);
    };
}