/* === S Y N F I G ========================================================= */
/*!	\file audiocontainer.cpp
**	\brief Audio Container implementation File
**
**	$Id$
**
**	\legal
**	Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
**
**	This package 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 package 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.
**	\endlegal
*/
/* ========================================================================= */

/* === H E A D E R S ======================================================= */

#ifdef USING_PCH
#	include "pch.h"
#else
#ifdef HAVE_CONFIG_H
#	include <config.h>
#endif

#include <algorithm>
#include <sigc++/sigc++.h>

#include <ETL/stringf>
#include <ETL/clock>
//#include <ETL/thread>
#include <glibmm/thread.h>

#include <synfig/general.h>

#include <glibmm/main.h>

#include "audiocontainer.h"

#include <cstdio>
#include <sys/stat.h>
#include <errno.h>

#include <set>
#include <vector>

#include <gui/localization.h>

#endif

/* === U S I N G =========================================================== */

using namespace std;
using namespace etl;
using namespace synfig;

/* === M A C R O S ========================================================= */
#ifdef __WIN32
#else //linux...
#define AUDIO_OUTPUT	FSOUND_OUTPUT_OSS
#endif

/* === G L O B A L S ======================================================= */
//const double delay_factor = 3;
//Warning: Unused variable delay_factor
/* === P R O C E D U R E S ================================================= */

/* === M E T H O D S ======================================================= */

/* === E N T R Y P O I N T ================================================= */

//Help constructing stuff
struct FSOUND_SAMPLE;
using studio::AudioContainer;

bool build_profile(FSOUND_SAMPLE */*sample*/, double &/*samplerate*/, std::vector<char> &/*samples*/)
	{ return false; } // not implemented


struct scrubinfo {};

//----- AudioProfile Implementation -----------
void studio::AudioProfile::clear()
{
	samplerate = 0;
	samples.clear();
}

handle<AudioContainer>	studio::AudioProfile::get_parent() const
{
	return parent;
}

void studio::AudioProfile::set_parent(etl::handle<AudioContainer> i)
{
	parent = i;
}

double studio::AudioProfile::get_offset() const
{
	if(parent)
		return parent->get_offset();
	return 0;
}

//---------- AudioContainer definitions ---------------------

struct studio::AudioContainer::AudioImp
{
	//Sample load time information
	FSOUND_SAMPLE *		sample;
	int					channel;
	int					sfreq;
	int					length;

	//Time information
	double				offset; //time offset for playing...

	//We don't need it now that we've adopted the play(t) time schedule...
	//current time... and playing info....
	//float				seekpost;
	//bool				useseekval;

	//Make sure to sever our delayed start if we are stopped prematurely
	sigc::connection	delaycon;

	//Action information
	bool				playing;
	double				curscrubpos;
	etl::clock			timer;	//for getting the time diff between scrub input points

	//Scrubbing information...
	//the current position of the sound will be sufficient for normal stuff...
	scrubinfo			*scrptr;

	bool is_scrubbing() const {return scrptr != 0;}
	void set_scrubbing(bool /*s*/) { scrptr = 0; }

	//helper to make sure we are actually playing (and to get a new channel...)
	bool init_play() { return false; }

public: //structors
	AudioImp():
		sample(0),
		channel(0),
		sfreq(0),
		length(0),
		offset(0),
		playing(false),
		curscrubpos(),
		scrptr(0)
	{ } //reuse the channel...

	~AudioImp()
		{ clear(); }

public: //helper/accessor funcs
	bool start_playing_now() //callback for timer...
		{ return false; } //so the timer doesn't repeat itself
	bool isRunning()
		{ return false; }
	bool isPaused()
		{ return false; }

public: //forward interface

	//Accessors for the offset - in seconds
	const double &get_offset() const
		{return offset;}
	void set_offset(const double &d)
		{ offset = d; }

	//Will override the parameter timevalue if the sound is running, and not if it's not...
	bool get_current_time(double &/*out*/)
		{ return isRunning(); }

	//Big implementation functions...
	bool load(const std::string &filename, const std::string &filedirectory);
	void clear();

	//playing functions
	void play(double t);
	void stop();

	//scrubbing functions
	void start_scrubbing(double t);
	void scrub(double t);
	void stop_scrubbing();

	double scrub_time()
		{ return curscrubpos; }
};

//--------------- Audio Container definitions --------------------------
studio::AudioContainer::AudioContainer():
	imp(NULL),
	profilevalid()
{ }

studio::AudioContainer::~AudioContainer()
{
	if(imp) delete (imp);
}

bool studio::AudioContainer::load(const std::string &filename,const std::string &filedirectory)
{
	if(!imp)
	{
		imp = new AudioImp;
	}

	profilevalid = false;
	return imp->load(filename,filedirectory);
}

handle<studio::AudioProfile> studio::AudioContainer::get_profile(float /*samplerate*/)
	{ return handle<studio::AudioProfile>(); }

void studio::AudioContainer::clear()
{
	if (imp) { delete imp; imp = 0; }
	profilevalid = false;
}

void studio::AudioContainer::play(double t)
	{ if(imp) imp->play(t); }

void studio::AudioContainer::stop()
	{ if(imp) imp->stop(); }

bool studio::AudioContainer::get_current_time(double &out)
{
	if(imp) return imp->get_current_time(out);
	else return false;
}

void AudioContainer::set_offset(const double &s)
	{ if(imp) imp->set_offset(s); }

double AudioContainer::get_offset() const
{
	static double zero = 0;
	return imp ? imp->get_offset() : zero;
}

bool AudioContainer::is_playing() const
	{ return imp && imp->playing; }

bool AudioContainer::is_scrubbing() const
	{ return imp && imp->is_scrubbing(); }

void AudioContainer::start_scrubbing(double t)
	{ if (imp) imp->start_scrubbing(t); }

void AudioContainer::stop_scrubbing()
	{ if(imp) imp->stop_scrubbing(); }

void AudioContainer::scrub(double t)
	{ if(imp) imp->scrub(t); }

double AudioContainer::scrub_time() const
	{ return imp ? imp->scrub_time() : 0; }

bool AudioContainer::isRunning() const
	{ return imp && imp->isRunning(); }

bool AudioContainer::isPaused() const
	{ return imp && imp->isPaused(); }

//----------- Audio imp information -------------------

bool studio::AudioContainer::AudioImp::load(const std::string &/*filename*/,
											const std::string &/*filedirectory*/)
{
	clear();
	return false;
}

void studio::AudioContainer::AudioImp::play(double /*t*/)
	{ }

void studio::AudioContainer::AudioImp::stop()
{
	delaycon.disconnect();
	playing = false;
}

void studio::AudioContainer::AudioImp::clear()
{
	channel = 0;
	sample = 0;
	playing = false;
}

void studio::AudioContainer::AudioImp::start_scrubbing(double /*t*/)
{
	if (playing) stop();
	set_scrubbing(true);
}

void studio::AudioContainer::AudioImp::stop_scrubbing()
{
	if (is_scrubbing()) set_scrubbing(false);
	curscrubpos = 0;
}

void studio::AudioContainer::AudioImp::scrub(double /*t*/)
	{ }
