#ifndef __SIGNALGENERATOR_HPP__
#define __SIGNALGENERATOR_HPP__

#include <unistd.h>
#include "efw/ExperimentFlow.hpp"
#include "config/FailConfig.hpp"
#include "util/Logger.hpp"
#include "util/ElfReader.hpp"
#include <math.h>

static const float MYPI = 3.14159265358979323846f;

/**
 * @file
 * @brief A simple signal generator
 */

/**
 * @class SignalForm
 * @brief Abstract signal form to be generated by a SignalGenerator
 * @see SignalGenerator
 */
class SignalForm {

	mutable fail::Logger m_log;

public:
	/**
	 * Signalgenerator just calls the calculate method of a derived signal
	 * form.
	 */
	virtual double calculate(void) const = 0;

protected:
	SignalForm() : m_log("SigForm", false) {};

	fail::simtime_t ticksPerSecond(void) const
	{
		fail::simtime_t ticksPerSec = fail::simulator.getTimerTicksPerSecond();
		if (ticksPerSec == 0) {
			m_log << "Warning: Timer ticks per second equals 0" << std::endl;
		}
		return ticksPerSec;
	}
};


/**
 * @class SignalGenerator
 * @brief Plugin to provide signal patterns on a specific memory location
 *
 * This plugin is intended for use in the realtime systems lecture.
 * Based on the simulator tick, multiple sinus signal are generated.
 */
class SignalGenerator : public fail::ExperimentFlow
{
private:
	const fail::ElfSymbol m_symbol; //!< the target's memory symbol the plugin is listening on to generate value
	fail::Logger m_log; //!< debug output
	const SignalForm  *const m_signal; //!< Abstract signal form provided by the user
public:
	/**
	 * Constructor
	 *
	 * @param symbol The resulting signal value is placed in the SUT symbol
	 * @param signal The Signal form to be generated @see SignalForm
	 */
	SignalGenerator( const fail::ElfSymbol & symbol, SignalForm *signal ) :   m_symbol(symbol), m_log("SigGen", false), m_signal(signal){}

	bool run();

private:
	/**
	 * Handle the memory event
	 */
	uint8_t handleEvent(void);
};

#include <vector>

/**
 * @class Sine
 * @brief A sine wave signal
 *
 * Generating superimposed sine waves,
 * according to the SineParams_t parameters.
 */
class Sine : public SignalForm
{
public:

	//! Parameter set for a single wave
	struct SineParams_t {
		double freq_in_hz; //!< Freqency in Hz
		double amplitude; //!< between 0..1
		SineParams_t(double f, double a) : freq_in_hz(f), amplitude(a) {};
	};

	//! Multiple sine waves can be superimposed (e.g., summed up)
	typedef std::vector<SineParams_t> SineParamsList_t;
	SineParamsList_t m_params;

	Sine(const SineParams_t param);
	Sine(const SineParamsList_t paramlist) : m_params(paramlist) {};

	/**
	 * Calculate sinus value of frequency freq_hertz based on the given
	 * simulator time t (in seconds):
	 * \f$x = sin(2 pi f t)\f$
	 **/
	double sinus(double freq_hertz, double t) const
	{
		return sin((2. * MYPI * freq_hertz)  * t);
	}

	double calculate(void) const;
};

#endif // __SIGNALGENERATOR_HPP__
