
//	System Includes
#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
	#include <AudioToolbox/AudioToolbox.h>
#else
	#include <AudioToolbox.h>
#endif
#include "MatchAudioChannelLayoutTagWithChannels.h"
#include <stdlib.h>

/*
MatchAudioChannelLayoutTagWithChannels determines whether an AudioChannelLayoutTag 
matches the channel descriptions in an AudioChannelLayout.
*/

Boolean MatchAudioChannelLayoutTagWithChannels(
	AudioChannelLayoutTag inTag, 
	AudioChannelLayout* inLayout)
{
	UInt32 inNumChannels = inLayout->mNumberChannelDescriptions;
	
	if (inNumChannels != AudioChannelLayoutTag_GetNumberOfChannels(inTag))
		return false;
	
	OSStatus err = noErr;
	UInt32 outSize;
	err = AudioFormatGetPropertyInfo(kAudioFormatProperty_ChannelLayoutForTag, sizeof(inTag), &inTag, &outSize);
	if (err) return false;
	
	UInt32 byteSize = offsetof(AudioChannelLayout, mChannelDescriptions[inNumChannels]);
	AudioChannelLayout *testLayout = (AudioChannelLayout*)calloc(1, byteSize);

	err = AudioFormatGetProperty(kAudioFormatProperty_ChannelLayoutForTag, sizeof(inTag), &inTag, &outSize, testLayout);
	if (err) {
		free(testLayout);
		return false;
	}
	
	if (testLayout->mNumberChannelDescriptions != inNumChannels)
	{
		free(testLayout);
		return false;
	}
	
	for (UInt32 i=0; i<inNumChannels; ++i)
	{
		Boolean found = false;
		for (UInt32 j = 0; j<inNumChannels; ++j)
		{
			if (inLayout->mChannelDescriptions[i].mChannelLabel == testLayout->mChannelDescriptions[i].mChannelLabel)
			{
				found = true;
				break;
			}
		}
		if (!found) {
			free(testLayout);
			return false;
		}
	}
	free(testLayout);
	return true;
}

/*
FindTagForMatchAudioChannelLayoutInAnyOrder determines whether there is any AudioChannelLayoutTag that contains the same
channel labels as inLayout. If there is the first one that matches is returned in outTag and the function returns true.
Otherwise the function returns false.
*/

Boolean FindTagForMatchAudioChannelLayoutInAnyOrder(AudioChannelLayout* inLayout, AudioChannelLayoutTag &outTag)
{
	UInt32 inNumChannels = inLayout->mNumberChannelDescriptions;

	OSStatus err = noErr;
	UInt32 outSize;
	err = AudioFormatGetPropertyInfo(kAudioFormatProperty_TagsForNumberOfChannels, sizeof(UInt32), &inNumChannels, &outSize);
	if (err) return false;

	AudioChannelLayoutTag* tags = (AudioChannelLayoutTag*)calloc(1, outSize);
	
	err = AudioFormatGetProperty(kAudioFormatProperty_TagsForNumberOfChannels, sizeof(UInt32), &inNumChannels, &outSize, tags);
	if (err) {
		free(tags);
		return false;
	}
	
	UInt32 numTags = outSize / sizeof(AudioChannelLayoutTag);
	
	for (UInt32 i = 0; i<numTags; ++i)
	{
		Boolean success = MatchAudioChannelLayoutTagWithChannels(tags[i], inLayout);
		if (success) {
			outTag = tags[i];
			return true;
		}
	}
	
	return false;
}
