#include "portaudiocpp/Device.hxx"

#include <cstddef>

#include "portaudiocpp/HostApi.hxx"
#include "portaudiocpp/System.hxx"
#include "portaudiocpp/Exception.hxx"

namespace portaudio
{

        // -------------------------------------------------------------------------------

        Device::Device(PaDeviceIndex index) : index_(index)
        {
            if (index == paNoDevice)
                info_ = NULL;
            else
                info_ = Pa_GetDeviceInfo(index);
        }

        Device::~Device()
        {
        }

        PaDeviceIndex Device::index() const
        {
            return index_;
        }

        const char *Device::name() const
        {
            if (info_ == NULL)
                return "";

            return info_->name;
        }

        int Device::maxInputChannels() const
        {
            if (info_ == NULL)
                return 0;

            return info_->maxInputChannels;
        }

        int Device::maxOutputChannels() const
        {
            if (info_ == NULL)
                return 0;

            return info_->maxOutputChannels;
        }

        PaTime Device::defaultLowInputLatency() const
        {
            if (info_ == NULL)
                return static_cast<PaTime>(0.0);

            return info_->defaultLowInputLatency;
        }

        PaTime Device::defaultHighInputLatency() const
        {
            if (info_ == NULL)
                return static_cast<PaTime>(0.0);

            return info_->defaultHighInputLatency;
        }

        PaTime Device::defaultLowOutputLatency() const
        {
            if (info_ == NULL)
                return static_cast<PaTime>(0.0);

            return info_->defaultLowOutputLatency;
        }

        PaTime Device::defaultHighOutputLatency() const
        {
            if (info_ == NULL)
                return static_cast<PaTime>(0.0);

            return info_->defaultHighOutputLatency;
        }

        double Device::defaultSampleRate() const
        {
            if (info_ == NULL)
                return 0.0;

            return info_->defaultSampleRate;
        }

        // -------------------------------------------------------------------------------

        bool Device::isInputOnlyDevice() const
        {
            return (maxOutputChannels() == 0);
        }

        bool Device::isOutputOnlyDevice() const
        {
            return (maxInputChannels() == 0);
        }

        bool Device::isFullDuplexDevice() const
        {
            return (maxInputChannels() > 0 && maxOutputChannels() > 0);
        }

        bool Device::isSystemDefaultInputDevice() const
        {
            return (System::instance().defaultInputDevice() == *this);
        }

        bool Device::isSystemDefaultOutputDevice() const
        {
            return (System::instance().defaultOutputDevice() == *this);
        }

        bool Device::isHostApiDefaultInputDevice() const
        {
            return (hostApi().defaultInputDevice() == *this);
        }

        bool Device::isHostApiDefaultOutputDevice() const
        {
            return (hostApi().defaultOutputDevice() == *this);
        }

        // -------------------------------------------------------------------------------

        bool Device::operator==(const Device &rhs) const
        {
            return (index_ == rhs.index_);
        }

        bool Device::operator!=(const Device &rhs) const
        {
            return !(*this == rhs);
        }

        // -------------------------------------------------------------------------------

        HostApi &Device::hostApi()
        {
            // NOTE: will cause an exception when called for the null device
            if (info_ == NULL)
                throw PaException(paInternalError);

            return System::instance().hostApiByIndex(info_->hostApi);
        }

        const HostApi &Device::hostApi() const
        {
            // NOTE; will cause an exception when called for the null device
            if (info_ == NULL)
                throw PaException(paInternalError);

            return System::instance().hostApiByIndex(info_->hostApi);
        }

        // -------------------------------------------------------------------------------

} // namespace portaudio
