/*
 *  CAAUMIDIMapManager.cpp
 *
	$Log: CAAUMIDIMapManager.cpp,v $
	Revision 1.18  2004/12/13 20:56:46  crogers
	bracket Print() method with #if DEBUG to avoid compile errors
	
	Revision 1.17  2004/12/09 03:07:27  bills
	some changes to API (including publish in C++ style)
	
	Revision 1.16  2004/11/24 02:26:00  cbruyns
	change to MIDI_Matches
	
	Revision 1.15  2004/11/13 02:16:39  bills
	add ReplaceAllMaps
	
	Revision 1.14  2004/11/12 02:31:56  bills
	use a ref, not a copy
	
	Revision 1.13  2004/11/06 03:34:47  bills
	fix build problem
	
	Revision 1.12  2004/11/04 23:23:42  cbruyns
	cleaned up includes
	
	Revision 1.11  2004/11/04 21:50:22  cbruyns
	moved save and restore out of map manager.  also ignore previous CVS notes, those were for the CAServices project not these source files.
	
	Revision 1.10  2004/11/04 19:56:00  cbruyns
	moved the midi map files to the Components target
	removed AudioToolbox from AudioUnit target
	
	Revision 1.9  2004/11/02 23:45:29  cbruyns
	notes added for save & restore maps
	
	Revision 1.8  2004/10/28 21:19:34  cbruyns
	remove printfs
	
	Revision 1.7  2004/10/27 08:20:10  cbruyns
	start of save restore
	
	Revision 1.6  2004/10/26 20:56:28  cbruyns
	updated mapping passing
	
	Revision 1.5  2004/10/22 00:23:20  cbruyns
	changed get all midi maps - again
	
	Revision 1.4  2004/10/21 23:27:44  cbruyns
	new remove and return all
	
	Revision 1.3  2004/10/19 22:17:33  cbruyns
	map manager with vector
	
	Revision 1.2  2004/10/19 22:04:27  cbruyns
	map manager with vector
	
	Revision 1.1  2004/10/15 02:03:48  cbruyns
	first checkin
	
 *  Created by cynthia on 10/14/04.
 *  Copyright 2004 __MyCompanyName__. All rights reserved.
 *
 */


#include "CAAUMIDIMapManager.h"
#include <AudioToolbox/AudioUnitUtilities.h>

CAAUMIDIMapManager::CAAUMIDIMapManager()
{	
	hotMapping = false;	
}

void FillInMap (CAAUMIDIMap &map, AUBase &That)
{
	AudioUnitParameterInfo info;
	That.GetParameterInfo (map.mScope, map.mParameterID, info);
	
	if (map.IsSubRange()) {
		map.mMinValue = map.mSubRangeMin;
		map.mMaxValue = map.mSubRangeMax;
	} else {
		map.mMinValue = info.minValue;			
		map.mMaxValue = info.maxValue;		
	}
	
	map.mTransType = CAAUMIDIMap::GetTransformer(info.flags);
}

OSStatus	CAAUMIDIMapManager::SortedInsertToParamaterMaps	(AUParameterMIDIMapping *maps, UInt32 inNumMaps, AUBase &That)
{	
	for (unsigned int i = 0; i < inNumMaps; ++i) 
	{
		CAAUMIDIMap map(maps[i]);

		FillInMap (map, That);
		
		int idx = FindParameterIndex (maps[i]);
		if (idx > -1)
			mParameterMaps.erase(mParameterMaps.begin() + idx);

			// least disruptive place to put this is at the end
		mParameterMaps.push_back(map);
	}
	
	std::sort(mParameterMaps.begin(), mParameterMaps.end(), CompareMIDIMap());	
	
	return noErr;
}

void CAAUMIDIMapManager::GetHotParameterMap(AUParameterMIDIMapping &outMap )
{
	outMap = mHotMap;
}

void CAAUMIDIMapManager::SortedRemoveFromParameterMaps(AUParameterMIDIMapping *maps, UInt32 inNumMaps, bool &outMapDidChange)
{	
	if (hotMapping) {
		hotMapping = false;
	}

	outMapDidChange = false;
	for (unsigned int i = 0; i < inNumMaps; ++i) {
		int idx = FindParameterIndex (maps[i]);
		if (idx > -1) {
			//mParameterMaps[idx].Print();
			mParameterMaps.erase(mParameterMaps.begin() + idx);
			outMapDidChange = true;
		}
	}
}

void	CAAUMIDIMapManager::ReplaceAllMaps (AUParameterMIDIMapping* inMappings, UInt32 inNumMaps, AUBase &That)
{
	mParameterMaps.clear();

	for (unsigned int i = 0; i < inNumMaps; ++i) {
		CAAUMIDIMap mapping(inMappings[i]);

		FillInMap (mapping, That);
		mParameterMaps.push_back (mapping);
	}

	std::sort(mParameterMaps.begin(),mParameterMaps.end(), CompareMIDIMap());	
}

bool CAAUMIDIMapManager::HandleHotMapping(UInt8 	inStatus,
										  UInt8 	inChannel,
										  UInt8 	inData1,
										  AUBase	&That)
{ //used to set the hot map info

	if (inStatus == 0xf0) return noErr;
	
	if (!hotMapping) return false;
	hotMapping = false;

	mHotMap.mStatus = inStatus | inChannel;  
	mHotMap.mData1 = inData1; 
		
	SortedInsertToParamaterMaps (&mHotMap, 1, That);
	return true;
}

#if DEBUG

void CAAUMIDIMapManager::Print()
{
	for ( ParameterMaps::iterator i = mParameterMaps.begin(); i < mParameterMaps.end(); ++i) { 
		CAAUMIDIMap* listmap =  &(*i);		
		listmap->Print();		
	}		
}

#endif // DEBUG

void CAAUMIDIMapManager::GetMaps(AUParameterMIDIMapping* maps)
{
	int i = 0;
	for ( ParameterMaps::iterator iter = mParameterMaps.begin(); iter < mParameterMaps.end(); ++iter, ++i) { 
		AUParameterMIDIMapping &listmap =  (*iter);	
		maps[i] = listmap;	
	}
}

int CAAUMIDIMapManager::FindParameterIndex (AUParameterMIDIMapping &inMap)
{ 
	//used to get back hot mapping and one at a time maps, for ui
	
	int idx = 0;
	for ( ParameterMaps::iterator i = mParameterMaps.begin(); i < mParameterMaps.end(); ++i) { 
		CAAUMIDIMap & listmap =  (*i);
		if ( (listmap.mParameterID == inMap.mParameterID) && 
			 (listmap.mScope == inMap.mScope) && 
			 (listmap.mElement == inMap.mElement) )
		{ 
				return idx; 
		}
		idx++;
	}
	return -1;
}

bool CAAUMIDIMapManager::FindParameterMapEventMatch(	UInt8			inStatus,
														UInt8			inChannel,
														UInt8			inData1,
														UInt8			inData2,
														UInt32			inBufferOffset,
														AUBase&			inAUBase)
{
	bool ret_value = false;

	if (inStatus == 0x90 && !inData2)
		inStatus = 0x80 | inChannel;
	
	//used to test for midi matches once map is made
	CAAUMIDIMap tempMap;
	tempMap.mStatus = inStatus | inChannel;
	tempMap.mData1 = inData1;
	
	CompareMIDIMap compareObj;

	AudioUnitEvent event;
	event.mEventType = kAudioUnitEvent_ParameterValueChange;
	event.mArgument.mParameter.mAudioUnit = inAUBase.GetComponentInstance();
	
	ParameterMaps::iterator lower_iter = 
	std::lower_bound(mParameterMaps.begin(), mParameterMaps.end(), tempMap, compareObj);
	
	while (lower_iter < mParameterMaps.end()) 
	{
		CAAUMIDIMap & map = (*lower_iter);
		if (compareObj.Finish(map, tempMap)) 
			break;
		
		Float32 value;
		if (map.MIDI_Matches(inChannel, inData1, inData2, value))
		{	
			inAUBase.SetParameter ( map.mParameterID, map.mScope, map.mElement, 
									map.ParamValueFromMIDILinear(value), inBufferOffset);

			event.mArgument.mParameter.mParameterID = map.mParameterID;
			event.mArgument.mParameter.mScope = map.mScope;
			event.mArgument.mParameter.mElement = map.mElement;
			
			AUEventListenerNotify(NULL, NULL, &event);
			ret_value = true;
		}
		++lower_iter;
	}
	return ret_value;
}
