//
//  AudioBuffer.hpp
//  SwitchboardSDK
//
//  Created by Balázs Kiss on 2022. 02. 22..
//  Copyright © 2022. Synervoz Inc. All rights reserved.
//

#pragma once

#include <switchboard/export.h>
#include <switchboard_core/SwitchboardCore.hpp>

namespace switchboard {

/**
 * AudioBuffer template class.
 * @brief Provides an abstraction around raw audio buffers stored in memory.
 * @details Can be used with multiple data types such as AudioBuffer<float> or AudioBuffer<int16>.
 */
template <typename T>
class SWITCHBOARDSDK_EXPORT AudioBuffer final {
public:
    /**
     * @brief Creates an AudioBuffer instance from already allocated memory.
     *
     * @param numberOfChannels The number of channels.
     * @param numberOfFrames The number of frames.
     * @param isInterleaved Flag indicating whether audio data should be interleaved or non-interleaved. Only effective when numberOfChannels > 1.
     * @param sampleRate The sample rate of the audio buffer.
     * @param data Pointer to the pre-allocated stacked audio memory location.
     */
    AudioBuffer(uint numberOfChannels, uint numberOfFrames, bool isInterleaved, uint sampleRate, T** data);

    /**
     * @brief Creates a mono or interleaved AudioBuffer instance from already allocated memory.
     *
     * @param numberOfChannels The number of channels.
     * @param numberOfFrames The number of frames.
     * @param sampleRate The sample rate of the audio buffer.
     * @param data Pointer to the pre-allocated mono or interleaved memory location.
     */
    AudioBuffer(uint numberOfChannels, uint numberOfFrames, uint sampleRate, T* data);

    /**
     * @brief Returns the number of channels stored in the audio buffer.
     *
     * @returns The number of channels.
     */
    uint getNumberOfChannels() const;

    /**
     * @brief Returns the number of frames stored in the audio buffer.
     *
     * @returns The number of frames.
     */
    uint getNumberOfFrames() const;

    /**
     * @brief Sets the number of frames in the buffer.
     *
     * @param newNumberOfFrames The new number of frames.
     */
    void setNumberOfFrames(const uint newNumberOfFrames);

    /**
     * @brief Returns whether the audio buffer contains interleaved or non-interleaved data. Always false if the audio buffer is mono.
     *
     * @returns Boolean that is true if the audio data is interleaved, false otherwise or if the audio buffer is mono.
     */
    bool getIsInterleaved() const;

    /**
     * @brief Gets the sample rate of the audio buffer.
     *
     * @returns The sample rate.
     */
    uint getSampleRate() const;

    /**
     * @brief Sets the sample rate of the audio buffer.
     *
     * @param newSampleRate The new sample rate.
     */
    void setSampleRate(const uint newSampleRate);

    /**
     * @brief Returns whether the audio buffer is mono.
     *
     * @returns Boolean that is true if the audio data is single channel, false otherwise.
     */
    bool isMono() const;

    /**
     * @brief Returns a sample value from the audio buffer.
     *
     * @param channel The index of the channel.
     * @param sampleIndex The index of the sample.
     *
     * @returns The sample value.
     */
    T getSample(uint channel, uint sampleIndex) const;

    /**
     * @brief Sets a sample value in the audio buffer.
     *
     * @param channel The index of the channel.
     * @param sampleIndex The index of the sample.
     * @param value The sample value to set.
     */
    void setSample(uint channel, uint sampleIndex, T value);

    /**
     * @brief Returns a read pointer to the data for a channel in the audio buffer.
     *
     * @param channel The index of the channel.
     *
     * @returns The read pointer to the channel data.
     */
    const T* getReadPointer(uint channel) const;

    /**
     * @brief Returns a write pointer to the data for a channel in the audio buffer.
     *
     * @param channel The index of the channel.
     *
     * @returns The write pointer to the channel data.
     */
    T* getWritePointer(uint channel);

    /**
     * @brief Returns a read pointer to the data in the audio buffer.
     *
     * @returns The read pointer the the audio buffer's data.
     */
    const T** getReadPointer() const;

    /**
     * @brief Returns a write pointer to the data in the audio buffer.
     *
     * @returns The write pointer the the audio buffer's data.
     */
    T** getWritePointer();

    /**
     *  @brief Copies data from another AudioBuffer instance.
     *  @details Number of channels, number of frames and interleavedness have to be identical in the two audio buffers.
     *
     *  @param srcBuffer The source buffer to copy data from.
     */
    void copyFrom(const AudioBuffer<T>& srcBuffer);

    /**
     * @brief Sets all audio sample values to zero.
     */
    void clear();

private:
    uint numberOfChannels;
    uint numberOfFrames;
    bool isInterleaved;
    uint sampleRate;
    T** data;
    T* channelData;

    uint getBufferSizeBytes() const;
    uint getNumberOfBuffers() const;
};

}
