// 11 may 2017
#import "uipriv_darwin.h"
#import "attrstr.h"

struct addCTFeatureEntryParams {
	CFMutableArrayRef array;
	const void *tagKey;
	BOOL tagIsNumber;
	CFNumberType tagType;
	const void *tagValue;
	const void *valueKey;
	CFNumberType valueType;
	const void *valueValue;
};

static void addCTFeatureEntry(struct addCTFeatureEntryParams *p)
{
	CFDictionaryRef featureDict;
	CFNumberRef tagNum, valueNum;
	const void *keys[2], *values[2];

	keys[0] = p->tagKey;
	tagNum = NULL;
	values[0] = p->tagValue;
	if (p->tagIsNumber) {
		tagNum = CFNumberCreate(NULL, p->tagType, p->tagValue);
		values[0] = tagNum;
	}

	keys[1] = p->valueKey;
	valueNum = CFNumberCreate(NULL, p->valueType, p->valueValue);
	values[1] = valueNum;

	featureDict = CFDictionaryCreate(NULL,
		keys, values, 2,
		// TODO are these correct?
		&kCFCopyStringDictionaryKeyCallBacks,
		&kCFTypeDictionaryValueCallBacks);
	if (featureDict == NULL) {
		// TODO
	}
	CFArrayAppendValue(p->array, featureDict);

	CFRelease(featureDict);
	CFRelease(valueNum);
	if (p->tagIsNumber)
		CFRelease(tagNum);
}

static uiForEach otfArrayForEachAAT(const uiOpenTypeFeatures *otf, char a, char b, char c, char d, uint32_t value, void *data)
{
	__block struct addCTFeatureEntryParams p;

	p.array = (CFMutableArrayRef) data;
	p.tagIsNumber = YES;
	uiprivOpenTypeToAAT(a, b, c, d, value, ^(uint16_t type, uint16_t selector) {
		p.tagKey = kCTFontFeatureTypeIdentifierKey;
		p.tagType = kCFNumberSInt16Type;
		p.tagValue = (const SInt16 *) (&type);
		p.valueKey = kCTFontFeatureSelectorIdentifierKey;
		p.valueType = kCFNumberSInt16Type;
		p.valueValue = (const SInt16 *) (&selector);
		addCTFeatureEntry(&p);
	});
	return uiForEachContinue;
}

// TODO find out which fonts differ in AAT small caps and test them with this
static uiForEach otfArrayForEachOT(const uiOpenTypeFeatures *otf, char a, char b, char c, char d, uint32_t value, void *data)
{
	struct addCTFeatureEntryParams p;
	char tagcstr[5];
	CFStringRef tagstr;

	p.array = (CFMutableArrayRef) data;

	p.tagKey = *uiprivFUTURE_kCTFontOpenTypeFeatureTag;
	p.tagIsNumber = NO;
	tagcstr[0] = a;
	tagcstr[1] = b;
	tagcstr[2] = c;
	tagcstr[3] = d;
	tagcstr[4] = '\0';
	tagstr = CFStringCreateWithCString(NULL, tagcstr, kCFStringEncodingUTF8);
	if (tagstr == NULL) {
		// TODO
	}
	p.tagValue = tagstr;

	p.valueKey = *uiprivFUTURE_kCTFontOpenTypeFeatureValue;
	p.valueType = kCFNumberSInt32Type;
	p.valueValue = (const SInt32 *) (&value);
	addCTFeatureEntry(&p);

	CFRelease(tagstr);
	return uiForEachContinue;
}

CFArrayRef uiprivOpenTypeFeaturesToCTFeatures(const uiOpenTypeFeatures *otf)
{
	CFMutableArrayRef array;
	uiOpenTypeFeaturesForEachFunc f;

	array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
	if (array == NULL) {
		// TODO
	}
	f = otfArrayForEachAAT;
	if (uiprivFUTURE_kCTFontOpenTypeFeatureTag != NULL && uiprivFUTURE_kCTFontOpenTypeFeatureValue != NULL)
		f = otfArrayForEachOT;
	uiOpenTypeFeaturesForEach(otf, f, array);
	return array;
}