//------------------------------------------------------------------------
// Project     : VST SDK
//
// Category    : Helpers
// Filename    : public.sdk/source/vst/aaxwrapper/aaxwrapper.h
// Created by  : Steinberg, 08/2017
// Description : VST 3 -> AAX Wrapper
//
//-----------------------------------------------------------------------------
// This file is part of a Steinberg SDK. It is subject to the license terms
// in the LICENSE file found in the top-level directory of this distribution
// and at www.steinberg.net/sdklicenses. 
// No part of the SDK, including this file, may be copied, modified, propagated,
// or distributed except according to the terms contained in the LICENSE file.
//-----------------------------------------------------------------------------

/// \cond ignore

#pragma once

#include "public.sdk/source/vst/basewrapper/basewrapper.h"
#include "base/thread/include/flock.h"
#include <bitset>
#include <list>
#include <memory>

struct AAX_Plugin_Desc;
struct AAX_Effect_Desc;
class AAX_IComponentDescriptor;

class AAXWrapper_Parameters;
class AAXWrapper_GUI;

namespace Steinberg {
namespace Vst {
class IAudioProcessor;
class IEditController;
}
}

struct AAXWrapper_Context
{
	void* ptr[1]; // array of numDataPointers pointers
};

//------------------------------------------------------------------------
class AAXWrapper : public Steinberg::Vst::BaseWrapper,
                   public Steinberg::Vst::IComponentHandler2,
                   public Steinberg::Vst::IVst3ToAAXWrapper
{
public:
	// static creation method (will owned factory)
	static AAXWrapper* create (Steinberg::IPluginFactory* factory,
	                           const Steinberg::TUID vst3ComponentID, AAX_Plugin_Desc* desc,
	                           AAXWrapper_Parameters* p);

	AAXWrapper (Steinberg::Vst::BaseWrapper::SVST3Config& config, AAXWrapper_Parameters* p, AAX_Plugin_Desc* desc);
	~AAXWrapper ();

	//--- VST 3 Interfaces  ------------------------------------------------------
	// IHostApplication
	Steinberg::tresult PLUGIN_API getName (Steinberg::Vst::String128 name) SMTG_OVERRIDE;

	// IComponentHandler
	Steinberg::tresult PLUGIN_API beginEdit (Steinberg::Vst::ParamID tag) SMTG_OVERRIDE;
	Steinberg::tresult PLUGIN_API performEdit (
	    Steinberg::Vst::ParamID tag, Steinberg::Vst::ParamValue valueNormalized) SMTG_OVERRIDE;
	Steinberg::tresult PLUGIN_API endEdit (Steinberg::Vst::ParamID tag) SMTG_OVERRIDE;
	Steinberg::tresult PLUGIN_API restartComponent (Steinberg::int32 flags) SMTG_OVERRIDE;

	// IComponentHandler2
	Steinberg::tresult PLUGIN_API setDirty (Steinberg::TBool state) SMTG_OVERRIDE;
	Steinberg::tresult PLUGIN_API requestOpenEditor (
	    Steinberg::FIDString name = Steinberg::Vst::ViewType::kEditor) SMTG_OVERRIDE;
	Steinberg::tresult PLUGIN_API startGroupEdit () SMTG_OVERRIDE;
	Steinberg::tresult PLUGIN_API finishGroupEdit () SMTG_OVERRIDE;

	// FUnknown
	DEF_INTERFACES_2 (Steinberg::Vst::IComponentHandler2, Steinberg::Vst::IVst3ToAAXWrapper, BaseWrapper);
	REFCOUNT_METHODS (BaseWrapper);

	// AAXWrapper_Parameters callbacks
	void setGUI (AAXWrapper_GUI* gui) { mAAXGUI = gui; }
	Steinberg::int32 /*AAX_Result*/ getParameterInfo (const char* aaxId,
	                                                  Steinberg::Vst::ParameterInfo& paramInfo);
	Steinberg::int32 /*AAX_Result*/ ResetFieldData (Steinberg::int32 index, void* inData,
	                                                Steinberg::uint32 inDataSize);
	Steinberg::int32 Process (AAXWrapper_Context* instance);

	Steinberg::uint32 getNumMIDIports () const { return mCountMIDIports; }

	void setSideChainEnable (bool enable);
	bool generatePageTables (const char* outputFile);
	void setRenderingOffline (bool val);

	static void DescribeAlgorithmComponent (AAX_IComponentDescriptor* outDesc,
	                                        const AAX_Effect_Desc* desc,
	                                        const AAX_Plugin_Desc* pdesc);

	//--- ---------------------------------------------------------------------
	Steinberg::uint32 getNumAAXOutputs () const { return mAAXOutputs; }

	//------------------------------------------------------------------------
	// BaseWrapper overrides ---------------------------------
	//------------------------------------------------------------------------
	bool init () SMTG_OVERRIDE;
	bool _sizeWindow (Steinberg::int32 width, Steinberg::int32 height) SMTG_OVERRIDE;
	void onTimer (Steinberg::Timer* timer) SMTG_OVERRIDE;

	Steinberg::int32 _getChunk (void** data, bool isPreset) SMTG_OVERRIDE;
	Steinberg::int32 _setChunk (void* data, Steinberg::int32 byteSize, bool isPreset) SMTG_OVERRIDE;
	void setupProcessTimeInfo () SMTG_OVERRIDE;

//------------------------------------------------------------------------
private:
	void processOutputParametersChanges () SMTG_OVERRIDE;
	
	Steinberg::tresult setupBusArrangements (AAX_Plugin_Desc* desc);
	Steinberg::int32 countSidechainBusChannels (Steinberg::Vst::BusDirection dir,
	                                            Steinberg::uint64& scBusBitset);

	void guessActiveOutputs (float** out, Steinberg::uint32 num);
	void updateActiveOutputState ();

	AAXWrapper_Parameters* mAAXParams = nullptr;
	AAXWrapper_GUI* mAAXGUI = nullptr;

	Steinberg::uint32 mAAXOutputs = 0;

	Steinberg::Base::Thread::FLock mSyncCalls; // synchronize calls expected in the same thread in VST3
	AAX_Plugin_Desc* mPluginDesc = nullptr;
	Steinberg::uint32 mCountMIDIports = 0;

	// as of ProTools 12 (?) the context struct does no longer allow unused slots,
	//  so we have to generate indices into the context struct dynamically
	// context pointer to AAXWrapper always first
	static const Steinberg::int32 idxContext = 0;
	static const Steinberg::int32 idxBufferSize = 1;
	Steinberg::int32 idxInputChannels = -1;
	Steinberg::int32 idxOutputChannels = -1;
	Steinberg::int32 idxSideChainInputChannels = -1;
	Steinberg::int32 idxMidiPorts = -1;
	Steinberg::int32 idxAuxOutputs = -1;
	Steinberg::int32 idxMeters = -1;
	Steinberg::int32 numDataPointers = 0;

	static const Steinberg::int32 maxActiveChannels = 128;
	std::bitset<maxActiveChannels> mActiveChannels;
	std::bitset<maxActiveChannels> mPropagatedChannels;

	Steinberg::uint32 mCntMeters = 0;
	std::unique_ptr<Steinberg::Vst::ParamID[]> mMeterIds;

	struct GetChunkMessage;
	void* mainThread = nullptr;
	Steinberg::Base::Thread::FLock msgQueueLock;
	std::list<GetChunkMessage*> msgQueue;

	float mBypassGain = 1.0;
	float* mMetersTmp = nullptr;

	Steinberg::Vst::TQuarterNotes mLastPpqPos = 0;
	Steinberg::Vst::TQuarterNotes mNextPpqPos = 0;

	bool mWantsSetChunk = false;
	bool mSettingChunk = false;
	bool mSimulateBypass = false;
	bool mBypass = false;

	bool mPresetChanged = false;
	bool mBypassBeforePresetChanged = false;
	bool mWantsSetChunkIsPreset = false;

	friend class AAXWrapper_Parameters;
	friend class AAXWrapper_GUI;
};

/// \endcond
