/////////////////////////////////////////////////////////////////////////////
// File:        mod_audio.cpp
// Author:      Cesar Mauri Loba (cesar at crea-si dot com)
// Copyright:   (C) 2011 Cesar Mauri Loba - CREA Software Systems
//
//  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 3 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, see <http://www.gnu.org/licenses/>.
/////////////////////////////////////////////////////////////////////////////
#include "spcore/component.h"
#include "spcore/module.h"
#include "spcore/libimpexp.h"
#include "spcore/basictypes.h"

#include <wx/sound.h>

#include <string>

/**
	Quick and dirty audio player implementation based on wx.

	@todo consider better audio libraries such as:
		- http://audiere.sourceforge.net/
		- http://www.xiph.org/ao/doc/
		- http://connect.creativelabs.com/openal/default.aspx
		- http://sourceforge.net/projects/osalp/
		- http://ffmpeg.org/about.html
		- http://www.portaudio.com/docs.html (streaming only)
		- Gstreamer???

*/

using namespace spcore;

namespace mod_audio {

/**
	wav_player component

		Plays a WAV file.
		
	Input pins:
		play (any)			- Start playing
		stop (any)			- Stop playing
			
	Ouput pins:		

	Command line:
		[-p <path>]		Set initial path
*/
class WavPlayer : public CComponentAdapter {
public:
	static const char* getTypeName() { return "wav_player"; }
	virtual const char* GetTypeName() const { return WavPlayer::getTypeName(); }
	WavPlayer(const char * name, int argc, const char * argv[]) 
	: CComponentAdapter(name, argc, argv)
	{
		//m_opinElapsed= CTypeInt::CreateOutputPin("elapsed");
		//if (RegisterOutputPin(*m_opinElapsed)!= 0)
		//	throw std::runtime_error("error registering output pin");

		if (RegisterInputPin(*SmartPtr<IInputPin>(new InputPinPlay("play", *this), false))!= 0)
			throw std::runtime_error("error creating input pin play");

		if (RegisterInputPin(*SmartPtr<IInputPin>(new InputPinStop("stop", *this), false))!= 0)
			throw std::runtime_error("error creating input pin stop");

		// Process arguments
		if (argc) {			
			for (int i= 0; i< argc; ++i) {
				if (argv[i] && strcmp ("-p", argv[i])== 0) {
					// Path					
				
					++i;
					if (i< argc && argv[i]) {						
						wxString filePath(argv[i], wxConvUTF8);
						if (!m_sound.Create (filePath) && m_sound.IsOk()) {
							std::string error_msg("wav_player. Cannot open file:");
							error_msg+= argv[i];
							throw std::runtime_error(error_msg);
						}
					}
					else throw std::runtime_error("wav_player. Missing value for option -p");
				}			
				else if (argv[i] && strlen(argv[i])) {
					std::string error_msg("wave_player. Unknown option:");
					error_msg+= argv[i];
					throw std::runtime_error(error_msg);
				}
			}
		}
	}

private:
	virtual ~WavPlayer() {}

	class InputPinPlay : public CInputPinWriteOnly<CTypeAny, WavPlayer> {
	public:
		InputPinPlay (const char * name, WavPlayer & component)
		: CInputPinWriteOnly<CTypeAny, WavPlayer>(name, component) { }

		virtual int DoSend(const CTypeAny & ) {
			m_component->m_sound.Play();
			return 0;
		}
	};

	class InputPinStop : public CInputPinWriteOnly<CTypeAny, WavPlayer> {
	public:
		InputPinStop (const char * name, WavPlayer & component)
		: CInputPinWriteOnly<CTypeAny, WavPlayer>(name, component) { }

		virtual int DoSend(const CTypeAny & ) {
			m_component->m_sound.Stop();
			return 0;
		}
	};

	//
	// Data members
	//
	//SmartPtr<IOutputPin> m_opinElapsed;
	wxSound m_sound;
};

typedef ComponentFactory<WavPlayer> WavPlayerFactory;

/* ******************************************************************************
	audio  module
****************************************************************************** */
class AudioModule : public CModuleAdapter {
public:
	AudioModule() {
		//
		// components
		//
		RegisterComponentFactory(SmartPtr<spcore::IComponentFactory>(new WavPlayerFactory(), false));
	}

	~AudioModule() {
	}

	virtual const char * GetName() const { return "mod_audio"; }
};

static spcore::IModule* g_module= NULL;
SPEXPORT_FUNCTION spcore::IModule* module_create_instance()
{
	if (g_module== NULL) g_module= new AudioModule();
	return g_module;
}

};
