/******************************************************************************
 *
 * Project:  OpenCPN
 *
 ***************************************************************************
 *   Copyright (C) 2013 by David S. Register                               *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,  USA.         *
 ***************************************************************************
 */

#ifndef OCPN_SOUND_H__
#define OCPN_SOUND_H__

#include <functional>
#include <memory>
#include <string>

typedef std::function<void(void* userPtr)>  AudioDoneCallback;

/**
 * Sound  class supports playing a sound using synchronous or asynchronous
 * mode. Also supports sound device enumeration and various status
 * checks.
 *
 * Instances should normally be obtained using SoundFactory();
 */

class OcpnSound
{
    friend OcpnSound* SoundFactory(const char* system_command);

    public:

        virtual ~OcpnSound();

        /** Return number of available devices. */
        virtual int DeviceCount() const { return 1; }

        /** Return free-format info on device or "" if not available. */
        virtual std::string GetDeviceInfo(int deviceIndex) { return ""; }

        /** Return true if given device is an output device. */
        virtual bool IsOutputDevice(int deviceIndex) const { return true; }

        /**
         * Callback invoked as cb(userData) when audio stream is done and
         * drained. Should be called before Load() to be effective.
         *
         * Setting a non-null callback forces use of asynchronous mode.
         * Using a default, 0 argument restores to synchronous mode.
         *
         * NOTE: Callback might be invoked in a interrupt or thread context,
         * avoid anything which might block (I/O, memory allocation etc.).
         */
        virtual void SetFinishedCallback(AudioDoneCallback cb = 0,
                                         void* userData = 0);

        /**
         * Initiate the class, loading data from given path and using the
         * given device as output. DeviceIx == -1 implies default device.
         */
        virtual bool Load(const char* path, int deviceIx = -1) = 0;

         /**
         * De-Initiate the class, closing any open sound file,
         * preparing for a new Load() using the same OcpnSound instance
         */
        virtual void UnLoad() = 0;

        /**
         * Plays the file loaded by Load(). If a callback is defined using
         * SetFinishedCallback() the playback is asynchronous, otherwise the
         * call blocks until the playback has completed.
         *
         * If the sound has not been successfully Load()'ed or another sound
         * is currently played the request is dropped and logged returning
         * false.
         *
         * Otherwise in synchronous mode returns success/failure from
         * backend. Asynchronous mode returns true.
         */
        virtual bool Play(void) = 0;

        /**
         * Stop possible playback and unload buffers, allowed even if
         * not playing. Returns true if stopping is supported, else false.
         */
        virtual bool Stop() = 0;

        /** Reflects loading errors. */
        virtual bool IsOk() const { return m_OK; }

    protected:

        /** Default ctor. Load() must be called before actual usage. */
        OcpnSound();

        bool m_OK;
        int m_deviceIx;
        std::string m_soundfile;
        AudioDoneCallback m_onFinished;
        void* m_callbackData;

};

#endif // OCPN_SOUND_H__
