/*=============================================================================
	AUParamInfo.cpp
	
	$Log: AUParamInfo.cpp,v $
	Revision 1.10  2005/02/10 20:46:44  luke
	support arbitrary elements
	
	Revision 1.9  2004/11/19 03:20:45  cbruyns
	adding scope  into constructor
	
	Revision 1.8  2004/11/18 23:13:50  cbruyns
	took out only using global scope in CAAUParameter creation, instead passing inScope to that constructor
	
	Revision 1.7  2004/11/16 18:33:09  bills
	don't throw out of constructor (and add scope argument)
	
	Revision 1.6  2004/11/12 04:49:49  cbruyns
	keep list of parameterID's [bills]
	
	Revision 1.5  2004/08/20 22:58:51  bills
	add a GetParamInfo call
	
	Revision 1.4  2004/07/10 02:18:26  bills
	fix throws if no parameters
	
	Revision 1.3  2004/07/10 01:59:28  luke
	throw when no Params throws OSStatus(noErr)
	
	Revision 1.2  2004/07/10 01:51:17  luke
	code cleanup (bills)
	
	Revision 1.1  2004/07/10 01:42:27  bills
	some re-factoring
	

	created 9 July 2004, William Stewart
	Copyright (c) 2004 Apple Computer, Inc.  All Rights Reserved
	
	$NoKeywords: $
=============================================================================*/
#include "AUParamInfo.h"
#include "CAXException.h"

AUParamInfo::AUParamInfo (AudioUnit				inAU, 
							bool				inIncludeExpert, 
							bool				inIncludeReadOnly,
							AudioUnitScope		inScope,
							AudioUnitElement	inElement)
	: mAU (inAU),
	  mNumParams (0),
	  mParamListID(NULL),
	  mScope (inScope),
	  mElement (inElement)
{
	UInt32 size;
	OSStatus result = AudioUnitGetPropertyInfo(mAU, kAudioUnitProperty_ParameterList, inScope, mElement, &size, NULL);
		if (size == 0 || result) return;
	
	int nparams = size / sizeof(AudioUnitPropertyID);
	mParamListID = new AudioUnitParameterID[nparams];

	memset (mParamListID, 0xFF, size);

	AudioUnitParameterID *paramList = new AudioUnitParameterID[nparams];
	
	result = AudioUnitGetProperty(mAU, kAudioUnitProperty_ParameterList, mScope, mElement, paramList, &size);
	if (result) {
		delete [] mParamListID;
		delete [] paramList;
		mParamListID = NULL;
		return;
	}
	
	ParameterMap params;
	for (int i = 0; i < nparams; ++i) 
	{
		CAAUParameter auvp (mAU, paramList[i], mScope, mElement); // took out only using global scope in CAAUParameter creation
		const AudioUnitParameterInfo &paramInfo = auvp.ParamInfo();
			
		//	don't include if parameter can't be read or written
		if (!(paramInfo.flags & kAudioUnitParameterFlag_IsWritable) 
			&& !(paramInfo.flags & kAudioUnitParameterFlag_IsReadable))
			continue;

		// only include if expert params wanted
		if (!inIncludeExpert && auvp.IsExpert())
			continue;
		
		// only include if read only params are wanted
		if (!(paramInfo.flags & kAudioUnitParameterFlag_IsWritable) 
			&& (paramInfo.flags & kAudioUnitParameterFlag_IsReadable))
		{	
			if (!inIncludeReadOnly)
				continue;
		}
		
		mParamListID[mNumParams] = paramList[i];
		mNumParams++;
		
		// ok - if we're here, then we have a parameter we are going to display.
		UInt32 clump = 0;
		auvp.GetClumpID (clump);
		mParams[clump].push_back (auvp);
	}

	delete [] paramList;
}

AUParamInfo::~AUParamInfo()
{
	delete [] mParamListID;
}

UInt32			AUParamInfo::NumParamsForClump (UInt32 inClump) const
{ 
	ParameterMap::const_iterator it = mParams.find(inClump);
	if (it != mParams.end()) 
		return (*it).second.size();
	return 0;
}

const CAAUParameter*	AUParamInfo::GetParamInfo (AudioUnitParameterID inParamID) const
{
	for (ParameterMap::const_iterator it = mParams.begin(); it != mParams.end(); ++it) {
		const ParameterList &list = (*it).second;
		for (ParameterList::const_iterator iter = list.begin(); iter != list.end(); ++iter) {
			if (inParamID == (*iter).mParameterID) {
				return &(*iter);
			}
		}
	}
	return NULL;
}
