/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/***************************************************************************
 *            plugin.h
 *
 *  Sun Feb  7 14:11:40 CET 2016
 *  Copyright 2016 Bent Bisballe Nyeng
 *  deva@aasimon.org
 ****************************************************************************/

/*
 *  This file is part of PluginGizmo.
 *
 *  PluginGizmo is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License as published by
 *  the Free Software Foundation; either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  PluginGizmo 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 Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with PluginGizmo; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.
 */
#pragma once

#include <vector>
#include <string>

#include <cstdint>
#include <cstdlib>


#if defined(WIN32)
#define PG_EXPORT extern "C" __declspec(dllexport)
#else
#define PG_EXPORT extern "C" __attribute__((visibility("default")))
#endif

class MidiEvent;

//! Plugin categories.
enum class PluginCategory
{
	Unknown = 0,    // Unknown, category not implemented
	Effect,         // Simple Effect
	Synth,          // Instrument (Synths, samplers,...)
	Analysis,       // Scope, Tuner, ...
	Mastering,      // Dynamics, ...
	Spacializer,    // Panners, ...
	RoomFx,         // Delays and Reverbs
	SurroundFx,     // Dedicated surround processor
	Restoration,    // Denoiser, ...
	OfflineProcess, // Offline Process
	Shell,          // Plug-in is container of other plug-ins
	Generator       // ToneGenerator, ...
};

//! Abstract base-class for plugin implementations.
class Plugin {
public:
	//! Implement this to create a new plugin instance.
	static Plugin* create();

	//! Init function for setting up plugin parameters.
	virtual void init() = 0;

	//! Get current free-wheel mode.
	virtual bool getFreeWheel() const = 0;

	//! This method is called by the host when the free-wheel mode changes.
	virtual void onFreeWheelChange(bool freewheel) {}


	//! Call this to get current samplerate.
	virtual float getSamplerate() = 0;

	//! This method is called by the host when the samplerate changes.
	virtual void onSamplerateChange(float samplerate) = 0;


	//! Call this to get current frame-size.
	virtual std::size_t getFramesize() = 0;

	//! This method is called by the host when the frame-size changes.
	virtual void onFramesizeChange(std::size_t framesize) = 0;


	//! Call this to get current active state
	virtual bool getActive() = 0;

	//! This method is called by the host when the active state changes.
	virtual void onActiveChange(bool active) = 0;


	//! This method is called by the host to get the current state for storing.
	virtual std::string onStateSave() = 0;

	//! This method is called by the host when a new state has been loaded.
	virtual void onStateRestore(const std::string& config) = 0;


	//! This is method is called by the host to get the current latency.
	//! \param The latency in samples.
	virtual float getLatency() = 0;

	//! Call this method to signal a latency change to the host.
	//! \param latency The latency in samples.
	virtual void setLatency(float latency) = 0;


	//! Called by the the host to get the number of midi input channels.
	//! This must remain constant during the lifespan of the plugin instance.
	virtual std::size_t getNumberOfMidiInputs() = 0;

	//! Called by the the host to get the number of midi output channels.
	//! This must remain constant during the lifespan of the plugin instance.
	virtual std::size_t getNumberOfMidiOutputs() = 0;

	//! Called by the the host to get the number of audio input channels.
	//! This must remain constant during the lifespan of the plugin instance.
	virtual std::size_t getNumberOfAudioInputs() = 0;

	//! Called by the the host to get the number of audio output channels.
	//! This must remain constant during the lifespan of the plugin instance.
	virtual std::size_t getNumberOfAudioOutputs() = 0;


	//! Call this method to set midnam data for midi input
	virtual void setMidnamData(const std::vector<std::pair<int, std::string>>& midnam) {}

	//! Get unique plugin id.
	virtual std::string getId() = 0;

	// Functions used to set plugin information.
	virtual std::string getURI() = 0;
	virtual std::string getEffectName() = 0;
	virtual std::string getVendorString() = 0;
	virtual std::string getProductString() = 0;
	virtual std::string getHomepage() = 0;
	virtual PluginCategory getPluginCategory() = 0;

	//! Process callback.
	virtual void process(std::size_t pos,
	                     const std::vector<MidiEvent>& input_events,
	                     std::vector<MidiEvent>& output_events,
	                     const std::vector<const float*>& input_samples,
	                     const std::vector<float*>& output_samples,
	                     std::size_t count) = 0;


	//
	// Inline GUI (optional)
	//

	//! Return true if a GUI implementation is to be used.
	virtual bool hasInlineGUI()
	{
		return false;
	}

	struct InlineDrawContext
	{
		std::size_t width{0}; //< Width of the render buffer.
		std::size_t height{0}; //< Height of the render buffer.
		std::uint8_t* data{nullptr}; //< Allocated (or reused) RGBA buffer, filled by the plugin.
	};

#define pgzRGBA(r, g, b, a) ((b) | (g) << 8 | (r) << 16 | (a) << 24)

	//! Render call back.
	//! \param width The client area width as specified by the host.
	//! \param max_height The maximum allowed clieant area height as specified
	//!  by the host.
	//! \param context The render context filled an maintained by the plugin.
	virtual void onInlineRedraw(std::size_t width,
	                            std::size_t max_height,
	                            InlineDrawContext& context) {}

	//
	// GUI (optional)
	//

	//! Return true if a GUI implementation is to be used.
	virtual bool hasGUI()
	{
		return false;
	}

	//! Create new window.
	virtual void* createWindow(void *parent) { return nullptr; }

	//! Destroy window.
	virtual void onDestroyWindow() {}

	//! Show window.
	virtual void onShowWindow() {}

	//! Hide window.
	virtual void onHideWindow() {}

	//! Called regularly by host; process ui events.
	virtual void onIdle() {}

	//! Signal new window size to host.
	virtual void resizeWindow(std::size_t width, std::size_t height) = 0;

	//! Signal close window event to the host.
	virtual void closeWindow() = 0;
};
