//
//  NSStringHelpers.h
//  GlyphsCore
//
//  Created by Georg Seifert on 06.08.09.
//  Copyright 2009 schriftgestaltung.de. All rights reserved.
//

#import <GlyphsCore/GSBase.h>

#ifdef __cplusplus
extern "C" {
#endif

NS_ASSUME_NONNULL_BEGIN

#define MAX_UNICODE 0x10FFFF
/// Fractional digit count for color components.
#define GS_COLOR_COMPONENT_PRECISION 3 // 8-bit precision

/// TODO: Remove before public launch of Glyphs 4
#define GS_IMPORT_COLOR_COMPONENT(COMPONENT) \
((COMPONENT) > 1.0 ? [GSFloatToStringWithPrecision((COMPONENT) / 255.0, GS_COLOR_COMPONENT_PRECISION) floatValue] : (COMPONENT))

BOOL GSHasFraction(double v);

NSString *GSFloatToStringWithPrecision(CGFloat Float, uint8_t precision);

#ifndef GLYPHS_VIEWER
NSString *GSIntToString(int aInt);

size_t GSIntToBuffer(char *buffer, NSUInteger aInt);

NSString *GSFloatToStringFull(CGFloat Float, uint8_t precision);

void GSFloatToStringWithPrecisionToFile(FILE *file, CGFloat Float, uint8_t precision);

NSString *GSFloatToStringWithPrecisionMin(CGFloat Float, uint8_t precision, uint8_t minPrecision);
#endif

size_t GSFloatToStringWithPrecisionToBuffer(char *buffer, CGFloat inputFloat, uint8_t precision);

NSString *GSFloatToStringWithPrecisionLocalized(CGFloat Float, uint8_t precision);

size_t GSFloatToStringWithPrecisionToBufferMin(char *buffer, CGFloat Float, uint8_t precision, uint8_t minPrecision);

NSString *GSFloatToStringLocalized(CGFloat Float);

NSString *GSFloatToString(CGFloat Float);

#ifndef GLYPHS_VIEWER
NSString *GSPointToString(NSPoint P);

size_t GSIndexPathToBuffer(char *buffer, NSIndexPath *indexPath, BOOL addSpace);
#endif

NSString *GSStringFromIndexPath(NSIndexPath * _Nullable indexPath, BOOL addSpace);

NSIndexPath * _Nullable GSIndexPathFromString(NSString *string);

#ifndef GLYPHS_VIEWER
NSArray *GSIntListFromIndexPath(NSIndexPath *indexPath);
#endif

NSIndexPath * _Nullable GSIndexPathFromIntList(NSArray *intList);

NSString *GSTagStringFromFourCharCode(FourCharCode code);

/// Panics if the tag string is not four `unichar` characters long.
FourCharCode GSFourCharCodeFromTagString(NSString *tag);

/// Whether a glyph name contains a suffix delimited by glyph-name separators.
///
/// A match must end the name or be followed by `.`, `-`, or `_`.
/// Include the leading separator in `suffix`.
///
/// - Parameter glyphName: The glyph name to search.
/// - Parameter suffix: The suffix, including its leading separator. For example, `.tf` or `-ar`.
BOOL GSGlyphNameContainsSuffix(NSString * _Nullable glyphName, NSString *suffix);

@interface NSString (UUID)

+ (NSString *)UUID;

+ (NSString *)hexStringFromInt:(NSInteger)integer;

+ (NSString *)stringFromInt:(int)integer;

+ (NSString *)stringFromInt:(int)integer minWidth:(unsigned char)width;

#ifndef GLYPHS_VIEWER
+ (NSString *)hexStringFromUnsignedInteger:(NSUInteger)integer;
#endif

- (int)hexStringToInt;

+ (NSString *)stringWithChar:(UTF32Char)aChar;

- (NSString *)asciiString;

- (NSUInteger)countOfChar:(char)aChar;

+ (NSString *)pathForTemporaryFileWithPrefix:(NSString *)prefix;

- (nullable NSString *)absolutePathFromBaseDirPath:(NSString *)baseDirPath;

- (NSString *)relativePathFromBaseDirPath:(NSString *)baseDirPath;

//- (NSString *)encodeForPlist;

/**
 @param index A 16-bit character index, by reference. If the index points to a high surrogate character, it will be incremented on output so that the low surrogate is skipped.
 */
- (UTF32Char)character32AtIndex:(NSUInteger *)index;

+ (NSString *)encodeForFilePath:(NSString *)string;

+ (NSString *)encodeForASCII:(NSString *)string;

#if !GLYPHS_VIEWER
+ (NSString *)createStringForKey:(CGKeyCode)keyCode;
#endif

- (NSString *)stringByDeletingDotSuffix;

- (NSString *)stringByDeletingLastDotSuffix;

- (nullable NSString *)dotSuffix;

- (NSString *)stringByAppendingDotSuffix:(NSString *)suffix;

- (float)localizedFloatValue;

- (double)localizedDoubleValue;

/// this will treat '.' and ',' as decimal point
- (double)lenientDoubleValue;

- (NSString *)stringWithFirstLower;

- (NSString *)stringWithFirstUpper;

- (NSString *)camelCaseToSentenceCase;

- (NSRange)rangeOfLine:(NSUInteger)line;

- (NSUInteger)lineNumberAtIndex:(NSUInteger)idx;

- (void)lineNumber:(int *)lineNumber column:(int *)column atIndex:(NSUInteger)idx;

- (BOOL)isNumber;

- (BOOL)isAllDigits;

- (BOOL)isHexCapitalString;

- (BOOL)isHexCapitalStringWithLength:(NSUInteger)length;

- (NSString *)stringByRemovingCharactersInSet:(NSCharacterSet *)characterSet;

- (NSString *)stringByRemovingAccents;

- (BOOL)containsString:(NSString *)str options:(NSStringCompareOptions)options;

+ (NSString *)dateString;

- (BOOL)matchesDateFormat;

@end

@interface NSMutableString (Helper)

- (void)appendChar:(UTF32Char)ch;

@end

int writeIntBuffer(int n, char * restrict);

#ifndef GLYPHS_VIEWER
BOOL writeIntList(FILE *file, NSArray *values, GSFormatVersion format);

/// checks if the string needs quotes. &plain returns if there are non ascii chars that need UTF encoding
BOOL GSStringNeedsQuotes(NSString *value, BOOL *_Nullable isAscii);

BOOL GSCharNeedsQuotes(const char * _Nonnull string, size_t length, BOOL *_Nullable plain);

void writeKeyString(FILE *file, NSString * _Nonnull key);

void writeKey(FILE *file, const char *key);

size_t sWriteKey(char *buffer, const char *key);

BOOL writeStringEscape(FILE *file, NSString *value, BOOL escape);

size_t sWriteStringEscape(char *buffer, size_t maxLength, NSString *value, BOOL escape);

static inline BOOL writeKeyValueString(FILE *file, const char *key, NSString *value) {
	writeKey(file, key);
	return writeStringEscape(file, value, YES);
}

static inline BOOL writeKeyValueStringEscape(FILE *file, const char *key, NSString *value, BOOL escape) {
	writeKey(file, key);
	return writeStringEscape(file, value, escape);
}

static inline BOOL writeKeyValueStringSimple(FILE *file, const char *key, NSString *value) {
	return writeKeyValueStringEscape(file, key, value, NO);
}

BOOL writeKeyValueStringSimple(FILE *file, const char *key, NSString *Value);
BOOL writeKeyValueInt(FILE *file, const char *key, int Value);
size_t writeKeyValueIntBuffer(char *buffer, const char *key, int value);
BOOL writeValueInt(FILE *file, int Value);

BOOL writeKeyValueData(FILE *file, const char *key, NSData *Value);

BOOL writeKeyValueInt(FILE *file, const char *key, int Value);
BOOL writeFloat(FILE *file, CGFloat value, uint8_t precision);
BOOL writeKeyValueFloat(FILE *file, const char *key, CGFloat Value);
BOOL writeValueFloat(FILE *file, CGFloat value);
BOOL writeKeyValueFloatPrecision(FILE *file, const char *key, CGFloat Value, uint8_t precision);

typedef double (^FloatValue_t)(NSObject *);

BOOL writeKeyValueFloatList(FILE *file, const char *key, NSArray *values, GSFormatVersion format, FloatValue_t block);

typedef void (^ListBlock_t)(FILE *file, NSObject *value);

BOOL writeKeyValueListBlock(FILE *file, const char *key, NSArray *values, GSFormatVersion format, ListBlock_t block);

void writePosition(FILE *file, NSPoint pt, BOOL Compact);
void writeTuple2(FILE *file, const char *key, CGFloat value1, CGFloat value2, uint8_t precision);
size_t writeTuple2Buffer(char *buffer, const char *key, CGFloat value1, CGFloat value2, uint8_t precision);

void writeTuple2Format1(FILE *file, const char *key, CGFloat value1, CGFloat value2, uint8_t precision);

BOOL writeColor(FILE *file, const char *key, NSColor *color, GSFormatVersion format);

BOOL writeTransform(FILE *file, NSAffineTransformStruct ts, BOOL compact);
char *writeTransformToBuffer(NSAffineTransformStruct ts, char *buffer);

BOOL writeDateString(FILE *file, NSDate *date);
NSString *stringFromDate(NSDate *date);

uint8_t GSActualPrecision(CGFloat Float, uint8_t precision);
void endArray(FILE *file, GSFormatVersion format);

NSArray<NSValue *> *GSParseXYPairsAsPointValues(NSString *s);

#endif

NS_ASSUME_NONNULL_END

#ifdef __cplusplus
}
#endif
