//
//  CFOldStylePList.h
//  GlyphsCore
//
//  Created by Georg Seifert on 16.02.19.
//  Copyright © 2019 schriftgestaltung.de. All rights reserved.
//

#import <GlyphsCore/GSBase.h>

#ifndef CFOldStylePList_h
#define CFOldStylePList_h

typedef struct GSPlistParseInfo {
	unsigned char *curr;
	const unsigned char *end;
	const unsigned char *begin;
	bool inQuotedString; // this is used to be able to parse userData in node strings
	bool forceStringKeys;
	CFErrorRef error;
	CFAllocatorRef allocator;
	CFOptionFlags mutabilityOption;
	const unsigned char *fileName;
	CFMutableSetRef stringSet; // set of all strings involved in this parse; allows us to share non-mutable strings in the returned plist
} GSPlistParseInfo;

#define GSCheckKey(INFO, KEY) \
	GSCheckKeyWithLength(INFO, KEY, sizeof("" KEY "") - 1) // length = size of string without terminating \0

BOOL GSCheckKeyWithLength(GSPlistParseInfo *pInfo, const char *key, int length);
BOOL GSCreatePlistParseInfoWithFile(NSString *filePath, GSPlistParseInfo *pInfo);
void GSClosePlistParseInfoWithFile(GSPlistParseInfo *pInfo);
void GSCreatePlistParseInfoWithString(NSString *string, GSPlistParseInfo *pInfo);
void GSClosePlistParseInfoWithString(GSPlistParseInfo *pInfo);
void GSCreatePlistParseInfoWithBuffer(const unsigned char *line, NSUInteger length, GSPlistParseInfo *pInfo);
void GSClosePlistParseInfoWithBuffer(GSPlistParseInfo *pInfo);

void GSPropertyListSetErrorForInfo(GSPlistParseInfo *pInfo, NSString *suggestion, ...);
CFErrorRef GSPropertyListCreateError(CFIndex code, NSString *debugFormat, ...);
CFErrorRef GSPropertyListCreateErrorDetails(CFIndex code, NSString *description, NSString *suggestion);
UInt32 GSLineNumberStrings(GSPlistParseInfo *pInfo);

CFTypeRef GSParsePlistString(NSString *string, NSError **error) CF_RETURNS_RETAINED;
NSDictionary *GSParseStringDict(NSString *string, NSError **error);
NSArray *GSParseStringArray(NSString *string, NSError **error);

CFTypeRef GSParsePlistFile(NSString *filePath, NSError **error) CF_RETURNS_RETAINED;

NSDictionary *GSParseFileDict(NSString *filePath, NSError **error);
NSDictionary *GSParsePlistDict(GSPlistParseInfo *pInfo);
NSMutableDictionary *GSParsePlistDictMutable(GSPlistParseInfo *pInfo);

NSArray *GSParseFileArray(NSString *filePath, NSError **error) NS_RETURNS_RETAINED;

NSArray *GSParsePlistArray(GSPlistParseInfo *pInfo) NS_RETURNS_RETAINED;
NSString *GSParsePlistKey(GSPlistParseInfo *pInfo) NS_RETURNS_RETAINED;
NSString *GSParsePlistText(GSPlistParseInfo *pInfo) NS_RETURNS_RETAINED;
NSDate *GSParsePlistDate(GSPlistParseInfo *pInfo) NS_RETURNS_RETAINED;
CGFloat GSParsePlistFloat(GSPlistParseInfo *pInfo);
NSInteger GSParsePlistInteger(GSPlistParseInfo *pInfo);
BOOL GSParsePlistBool(GSPlistParseInfo *pInfo);
NSPoint GSParsePlistPoint(GSPlistParseInfo *pInfo);
BOOL GSParsePlistFloatListCallback(GSPlistParseInfo *pInfo, void (^callback)(CGFloat result));
BOOL GSParsePlistFloatList(GSPlistParseInfo *pInfo, CGFloat *values, NSInteger *count);
BOOL GSParsePlistTransform(GSPlistParseInfo *pInfo, NSAffineTransformStruct *transform);
NSObject *GSParsePlistObject(GSPlistParseInfo *pInfo);
NSColor *GSParsePlistColor(GSPlistParseInfo *pInfo, GSFormatVersion format);

BOOL GSAdvanceToNonSpace(GSPlistParseInfo *pInfo);

NSString *GSParseQuotedText(GSPlistParseInfo *pInfo);
#define skipWhiteSpace(pInfo)        \
	if (!GSAdvanceToNonSpace(pInfo)) \
		return 0;

#define skipWhiteSpaceFast(pInfo)        \
	if (!GSAdvanceToNonSpace(pInfo)) \
		return 0;

#endif /* CFOldStylePList_h */
