#ifndef NPLUGIN_H
#define NPLUGIN_H

#include <pluginloader.h>
#include <qarray.h>
#include <vector>

namespace Arts { class FFTScopeScope; class FFTScope; class RawScope; class RawScopeStereo; }

#define NOATUNPLUGIND void _pluginDelete() { delete this; }
#define NOATUNPLUGINC(classname) napp->libraryLoader()->_addHashCallback(#classname , (void(Plugin::*)())&classname::_pluginDelete)

class Playlist;
class Player;

class Plugin
{
public:
	Plugin();
	virtual ~Plugin();

	/**
	 * called directly after the plugin, just in case
	 * you want Noatun to be "ready" with your class
	 **/
	virtual void init();

	/**
	 * unload the plugin
	 * if it returns true, return from your function
	 * immediately and don't access members of this
	 * TODO
	 **/
	virtual bool unload();

	/**
	 * make multiple inheritence work
	 * only needed with playlist plugins
	 * generally "return this" in here
	 **/
	virtual PlayList *playlist() const { return 0; }
};

class UserInterface : public Plugin
{
public:
	UserInterface();
	virtual ~UserInterface();
};


class TimerThingy;

namespace Arts { class FFTScope; class FFTScopeStereo; }


class Visualization
{
friend class TimerThingy;
public:
	/**
	 * interval is how frequently the rescope
	 * will occur
	 * 0 means disabled
	 **/
	Visualization(int interval=125);
	virtual ~Visualization();

	/**
	 * start the timer, if it's 0, then this
	 * will do nothing.
	 **/
	virtual void start();
	/**
	 * stop the timer
	 **/
	virtual void stop();

	/**
	 * how long between each rescoping in milliseconds
	 **/
	int interval() const;
	
	/**
	 * set how long to wait
	 * the change takes effect immediately,
	 * unless it hadn't been start()ed beforehand
	 **/
	virtual void setInterval(int msecs);

	/**
	 * cause a rescoping to take effect immediately
	 **/
	virtual void timeout()=0;

private:
	int mTimeout;
	TimerThingy *mTimerThingy;
};

class FFTScope : public Visualization
{
public:
	FFTScope(int interval);
	
	/**
	 * the "width" of each scopeEvent
	 **/
	virtual int bands() const=0;

};

class StereoFFTScope : public FFTScope
{
public:
	StereoFFTScope(int timeout=250);
	virtual ~StereoFFTScope();
	
	/**
	 * called according to the timeout
	 * the two floats contain the data, with @p len items
	 * you override this yourself
	 **/
	virtual void scopeEvent(float *left, float *right, int len)=0;

	/**
	 * get the current data
	 * pass two vector<float>*, this will do the rest.
	 * do not allocate it beforehand.
	 * you must then delete the vectors
	 * @returns the amount of elements for both left and right
	 **/
	void scopeData(std::vector<float> *&left, std::vector<float> *&right);
	virtual void timeout();

	virtual int bands() const;

private:
	Arts::FFTScopeStereo *mScope;
	long mId;
};

class MonoFFTScope : public FFTScope
{
public:
	MonoFFTScope(int timeout=250);
	virtual ~MonoFFTScope();
	
	/**
	 * called according to the timeout
	 * the float contains the data, with @p len items
	 * you override this yourself
	 **/
	virtual void scopeEvent(float *data, int len)=0;

	/**
	 * get the current data
	 * pass a vector<float>*, this will do the rest.
	 * do not allocate it beforehand.
	 * you must then delete the vectors
	 * @returns the amount of elements for both left and right
	 **/
	void scopeData(std::vector<float> *&data);
	
	/**
	 * reimplemented from class Visualization, you
	 * should never need to reimplement this yourself
	 **/
	virtual void timeout();

	virtual int bands() const;
	
private:
	Arts::FFTScope *mScope;
	long mId;
};

class Scope : public Visualization
{
public:
	Scope(int interval);
	
	/**
	 * the "width" of each scopeEvent
	 **/
	virtual int samples() const=0;

	virtual void setSamples(int )=0;
};

class MonoScope : public Scope
{
public:
	MonoScope(int timeout=250);
	virtual ~MonoScope();
	
	/**
	 * called according to the timeout
	 * the float contains the data, with @p len items
	 * you override this yourself, and process the data
	 **/
	virtual void scopeEvent(float *data, int len)=0;

	/**
	 * get the current data
	 * pass a vector<float>*, this will do the rest.
	 * do not allocate it beforehand.
	 * you must then delete the vectors
	 * @returns the amount of elements for both left and right
	 **/
	void scopeData(std::vector<float> *&data);
	
	/**
	 * reimplemented from class Visualization, you
	 * should never need to reimplement this yourself
	 **/
	virtual void timeout();


	virtual int samples() const;
	virtual void setSamples(int);

	
private:
	Arts::RawScope *mScope;
	long mId;
};

class StereoScope : public Scope
{
public:
	StereoScope(int timeout=250);
	virtual ~StereoScope();
	
	/**
	 * called according to the timeout
	 * the float contains the data, with @p len items
	 * you override this yourself, and process the data
	 **/
	virtual void scopeEvent(float *left, float *right, int len)=0;

	/**
	 * get the current data
	 * pass a vector<float>*, this will do the rest.
	 * do not allocate it beforehand.
	 * you must then delete the vectors
	 * @returns the amount of elements for both left and right
	 **/
	void scopeData(std::vector<float> *&left, std::vector<float> *&right);
	
	/**
	 * reimplemented from class Visualization, you
	 * should never need to reimplement this yourself
	 **/
	virtual void timeout();


	virtual int samples() const;
	virtual void setSamples(int);

	
private:
	Arts::RawScopeStereo *mScope;
	long mId;
};

class SessionManagement : public Plugin
{
public:
	SessionManagement();
	virtual ~SessionManagement();

	virtual void restore();
};

#endif

