//
//  GSGlyphsInfo.h
//  Glyphs
//
//  Created by Georg Seifert on 20.1.08.
//  Copyright 2008 schriftgestaltung.de. All rights reserved.
//

#import <GlyphsCore/GSGlyph.h>

#ifndef LIBCORE
#import <GlyphsCore/GSSidebarItem.h>
#endif

NS_ASSUME_NONNULL_BEGIN

@class GSGlyphInfo;
@class GSFont;
@class GSLayer;
@class MGOrderedDictionary;
@class GSSidebarItem;
@class GSAnchor;

/**
 Common categories/subCategories
 */

extern NSString *GSGlyphCategoryLetter;
extern NSString *GSGlyphCategoryNumber;
extern NSString *GSGlyphCategoryPunctuation;
extern NSString *GSGlyphCategorySeparator;
extern NSString *GSGlyphCategorySymbol;
extern NSString *GSGlyphCategoryMark;
extern NSString *GSGlyphCategoryIcon;
extern NSString *GSGlyphCategorySFSymbol;
extern NSString *GSGlyphCategoryCorner;
extern NSString *GSGlyphCategorySmartGlyph;
extern NSString *GSGlyphCategoryPrivateUse;
extern NSString *GSGlyphSubcategoryNonspacing;
extern NSString *GSGlyphSubcategorySpacing;
extern NSString *GSGlyphSubcategorySpacingCombining;
extern NSString *GSGlyphSubcategoryLigature;
extern NSString *GSGlyphSubcategoryComposition;
extern NSString *GSGlyphSubcategoryFraction;
extern NSString *GSGlyphSubcategoryConjunct;
extern NSString *GSGlyphSubcategorySyllable;
extern NSString *GSGlyphSubcategoryHalfform;
extern NSString *GSGlyphSubcategoryMatra;
extern NSString *GSGlyphSubcategorySmart;

/** \brief GSGlyphsInfos: This is a singleton class to provide glyphInfo services.
 \ingroup common
 This is a singleton class to provide glyphInfo services.
 */
@interface GSGlyphsInfo : NSObject {

	NSMutableArray *_glyphInfos;
	NSMutableArray *_categories;
	NSMutableArray *_subCategories;
	NSMutableArray *_sidebarCategories;
	NSDictionary *_categoryIndexes;
	NSDictionary *_sidebarSubcategories;
	NSMutableDictionary<NSString *, GSSidebarItem *> *_name2Group;
	NSMutableDictionary *_name2Info;
	NSMutableDictionary *_unicode2Info;
	NSMutableArray *_scriptIDs;
	NSDictionary *_scriptIndexes;
	NSDictionary *_anchors;
	NSURL *_localURL;
	NSURL *_localInfoURL;
	NSDictionary *_iMatraCombinations;

@private
	BOOL _isGlobal;
	NSOperationQueue *_queue;
}
/** An array of glyph groups.

 This is used the build the filter tree in font view mode.
 */
@property (readonly, nonatomic) NSMutableArray *sidebarCategories;
@property (readonly, nonatomic) GSSidebarItem *languagesGroup;
/// The array containing the glyphs info data.
@property (strong, nonatomic) NSMutableArray *glyphInfos;
@property (readonly, nonatomic) NSMutableArray *scriptIDs;
@property (nonatomic, readonly) NSArray *categories;
@property (nonatomic, readonly) NSArray *subCategories;
@property (nonatomic, readonly, class) NSDictionary *defaultMetrics;
@property (readonly, nonatomic, class) NSDictionary *customParameterTypes;
@property (readonly, nonatomic, class) NSDictionary *customParameterMapping2to3;
@property (readonly, nonatomic, class) NSDictionary *customParameterMapping3to2;

@property (readonly, nonatomic, class) NSArray *customFontParameters;
@property (readonly, nonatomic, class) NSArray *customMasterParameters;
@property (readonly, nonatomic, class) NSArray *customInstanceParameters;
@property (readonly, nonatomic, class) NSArray *customVariableInstanceParameters;

@property (readonly, nonatomic, class) NSDictionary *basicFontInfoProperties;
/// The width classes
@property (readonly, nonatomic, class) NSDictionary *widthName2Classes;
@property (readonly, nonatomic, class) NSDictionary *widthClass2Names;
/// The weight classes
@property (readonly, nonatomic, class) NSDictionary *weightName2Classes;
@property (readonly, nonatomic, class) NSDictionary *weightClass2Names;
@property (readonly, nonatomic, class) NSDictionary *weightClass2NamesLegacy;
/// The width classes
@property (readonly, nonatomic, class) NSDictionary *localizedWidthName2Classes;
@property (readonly, nonatomic, class) NSDictionary *localizedWidthClass2Names;
/// The weight classes
@property (readonly, nonatomic, class) NSDictionary *localizedWeightName2Classes;
@property (readonly, nonatomic, class) NSDictionary *localizedWeightClass2Names;

@property (readonly, nonatomic) NSDictionary *name2Info;
@property (readonly, nonatomic) NSDictionary *unicode2Info;
//@property (readonly, nonatomic) NSDictionary *scriptRanges;
@property (readonly, nonatomic) NSSet *indicScripts;
@property (readonly, nonatomic) NSDictionary *iMatraCombinations;

/// Returns the shared GlyphsInfos object.
+ (GSGlyphsInfo *)sharedManager;

- (instancetype)initWithLocalFile:(NSURL *)localURL forFont:(nullable GSFont *)font;

+ (NSDateFormatter *)dateFormat;

+ (NSString *)applicationSupportFolder;

+ (NSString *)applicationSupportPath;

+ (NSArray *)applicationSupportPaths;

/** Returns the GSGlyphInfo for the glyph with Glyph.

 @param glyph The glyph.
 @return A GSGlyphInfo instance or nil.
 */
- (nullable GSGlyphInfo *)glyphInfoForGlyph:(GSGlyph *)glyph;

/** Returns the GSGlyphInfo for the glyph with Name.

 @param name The glyph name.
 @return A GSGlyphInfo instance or nil.
 */
- (nullable GSGlyphInfo *)glyphInfoForName:(NSString *)name;

/** Returns the GSGlyphInfo for the glyph with Unicode.

 @param unicode A unicode as Hex string.
 @return A GSGlyphInfo instance or nil.
 */
- (nullable GSGlyphInfo *)glyphInfoForUnicode:(NSString *)unicode;
- (nullable GSGlyphInfo *)glyphInfoForUnicodes:(NSOrderedSet *)unicodes;

/// Returns the index of the glyph in the database.
- (NSUInteger)glyphIndex:(GSGlyph *)glyph;

+ (BOOL)isPrivateUse:(UTF32Char)aChar;

+ (BOOL)isRTLScript:(nullable NSString *)script;

+ (BOOL)isCJKScript:(nullable NSString *)script;

+ (BOOL)isValidIdentifier:(NSString *)identifier;

+ (BOOL)isKeepNameCategory:(nullable NSString *)category;

/** Returns the name of the lowercase glyph name linked to the given uppercase name

 in most instances this is equivalent with `[name lowercaseString]` but there are some exceptions. e.g. A > a, KoppaArchaic > koppaArchaic
 @param name a upper case glyph name
 @return the matching lower case name
 */
- (nullable NSString *)lowerCaseName:(NSString *)name;

/**
 Updates the glyph info in the Glyph.

 @param glyph      The Glyph
 @param changeName Keep the name and only update unicode, categories and script
 */
- (void)updateGlyphInfo:(GSGlyph *)glyph changeName:(BOOL)changeName;

- (void)updateGlyphInfo:(GSGlyph *)glyph changeName:(BOOL)changeName changeUnicode:(BOOL)changeUnicode;

#ifndef GLYPHS_VIEWER

///

/** Generates missing anchors in the Layer.

 @param layer The Layer
 */
- (nullable NSArray<GSAnchor *> *)updateAnchors:(GSLayer *)layer;

#endif

/** Converts a name to a standardized name

 e.g. converts afii10017 to A-cy

 @param name The name.
 @return The nice-name.

 @see productionGlyphNameForName:
 */
- (NSString *)niceGlyphNameForName:(NSString *)name;

/** Converts a name to a production name

 @param name The name.
 @return The production name.
 @see niceGlyphNameForName:
 */
- (NSString *)productionGlyphNameForName:(NSString *)name;

- (NSString *)productionGlyphNameForGlyph:(GSGlyph *)glyph;

/**
 Converts a string into a list of glyph names

 This can be a space/comma/newline/tab separated list of names
 or
 a string of none ASCII codes (e.g. ideographs)

 @param string a string of glyph names or characters
 @returns a list of glyph names
 */
- (NSArray *)glyphNamesFromString:(NSString *)string;

/** Converts all glyph names to production names

 This is useful for OT-feature code

 @param string A string that contains glyph names like feature code.
 @return The string with converted names.
 */
- (NSString *)convertToLegacyNames:(NSString *)string font:(nullable GSFont *)font;

+ (NSString *)convertNames:(NSDictionary *)changeNames inString:(NSString *)featuresString;

- (void)fixASCIINames:(GSFont *)font;

- (NSString *)decomposeHangul:(unichar)s;

+ (BOOL)decomposeHangul:(unichar)s leadingConsonant:(unichar *)leadingConsonant vowel:(unichar *)vowel trailingConsonant:(unichar *)trailingConsonant;

+ (unichar)composeHangulLeadingConsonant:(unichar)leadingConsonant vowel:(unichar)vowel trailingConsonant:(unichar)trailingConsonant;

- (short)hangulComponentPositionForName:(NSString *)name;

- (short)hangulComponentPositionForUnichar:(unichar)aChar;

- (nullable NSArray *)hangulJamoGlyphsForPos:(short)pos;

+ (nullable NSString *)hangulPositionKeyForName:(NSString *)name;

+ (NSArray *)hangulFirstConsonants;
+ (NSArray *)hangulVowels;
+ (NSArray *)hangulFinalConsonants;

+ (nullable NSString *)CIDShortResourceName:(GSFont *)font;

+ (nullable NSString *)CIDFullResourceName:(GSFont *)font;

- (NSUInteger)indexOfObjectInScripts:(NSString *)script;

- (NSUInteger)indexOfObjectInCategories:(NSString *)category;

- (nullable NSMutableDictionary *)_subcategoriesForSidebarCategory:(nullable NSString *)category;

+ (nullable GSScriptTag)scriptTagForScriptID:(nullable GSScriptID)script;

+ (NSString *)scriptNameForScriptTag:(GSScriptTag)script;

+ (NSDictionary *)script2Tag;

+ (GSScriptID)scriptIDForScriptTag:(GSScriptTag)scriptTag;

+ (NSDictionary *)scriptSuffixes;

+ (NSDictionary *)languageScripts;

+ (NSSet *)scriptTags;

+ (NSSet *)indicScripts;

+ (NSArray *)languageData;

+ (nullable NSNumber *)macEncodingIDForTag:(NSString *)language;
+ (nullable NSNumber *)macLanguageIDForTag:(NSString *)language;
+ (nullable NSNumber *)winLanguageIDForName:(NSString *)language; // this shouldn’t be needed
+ (nullable NSNumber *)winLanguageIDForTag:(NSString *)language;

+ (nullable NSString *)langTagForName:(NSString *)name;
+ (nullable NSString *)langNameForTag:(NSString *)tag;

+ (nullable NSString *)winTagForLanguageID:(NSInteger)languageID;

+ (nullable NSString *)winNameForLanguageID:(NSInteger)languageID;

+ (nullable NSString *)languageNameForLanguageID:(NSInteger)languageID platformID:(NSInteger)platformID;

+ (nullable NSString *)languageTagForLanguageID:(NSInteger)languageID platformID:(NSInteger)platformID;

+ (int)propertyName2NameId:(NSString *)propertyName;

+ (nullable NSString *)nameId2PropertyName:(int)nameId;

+ (NSArray *)unicodeRanges;

+ (NSArray *)codePageRanges;

+ (nullable NSString *)closestWeightClass:(int)weightClass;

- (nullable NSString *)ligaNameForComponents:(nullable NSArray<NSString *> *)componentNames;

- (nullable NSArray *)componentsForLigaName:(NSString *)ligaName font:(nullable GSFont *)font;

+ (nullable NSString *)langSuffixForName:(NSString *)name;

+ (NSArray *)blueValues:(NSArray *)alignmentZones;

+ (NSArray *)otherBlues:(NSArray *)alignmentZones;

/// Returns a file name suitable for the given glyph name.
///
/// The file name extension (`.glyph`) is not included in the return value.
+ (NSString *)glyphNameToFileName:(NSString *)glyphName;

+ (BOOL)isASCIIString:(NSString *)string;

+ (NSArray<NSColor *> *)labelColors;

/// Returns the script tag formatted as a script identifier if no identifier is known for the given tag.
+ (NSString *)scriptIdentifierForScriptTag:(NSString *)scriptTag;

/// Returns an array with the language tag formatted as a language identifier if no identifier is known for the given tag.
+ (NSArray<NSString *> *)languageIdentifiersForLanguageTag:(NSString *)languageTag;

+ (NSArray<NSNumber *> *)variationSelectors;

/**
 StandardizedVariants.txt
 keys are glyph names for the first column, values is a list of (VS, name)
 */
+ (NSDictionary *)defaultVariationSelectors;

+ (BOOL)validateDefaultName:(nullable NSString *)value key:(NSString *)key minLength:(NSUInteger)minLength maxLength:(NSUInteger)maxLength error:(NSError * _Nullable *)error;

+ (BOOL)validatePostScriptName:(id _Nonnull *_Nonnull)ioValue error:(NSError * _Nullable *)error;

/**
 Removes all illegal parts from the file name and masks reserved file name parts
 */
+ (NSString *)validFileName:(NSString *)fileName;

+ (NSCharacterSet *)illegalFileNameCharacters;

+ (NSCharacterSet *)illegalPostScriptNameCharacters;

+ (NSCharacterSet *)illegalNameCharacters;

+ (void)registerPlaceholderFont:(NSString *)fontPath forScript:(NSString *)script;

+ (void)removePlaceholderFontForScript:(NSString *)script;

+ (nullable NSFont *)fontForScript:(NSString *)script size:(CGFloat)size;

+ (NSDictionary *)customParameterDescriptions;

#ifndef GLYPHS_LITE
+ (void)addType:(nonnull id)typeKey forParameter:(NSString *)parameterName forClass:(Class)infoClass;

+ (void)addDescription:(NSString *)description forParameter:(NSString *)parameterKey;
#endif

#pragma mark - Deprecated (Glyphs 3 compatibility)

- (instancetype)initWithLocalFile:(NSURL *)localURL GSDeprecated("initWithLocalFile:forFont:");
- (BOOL)updateAnchor:(GSLayer *)layer GSDeprecated("updateAnchors:");

@end

@interface GSGlyph (ApplyGlyphInfo)

/// Applies a record from the Glyph Info Database.
///
/// Glyph info stored as glyph-local overrides is preserved.
/// The name and Unicode values are changed only when requested.
/// An established private-use glyph name is preserved.
///
/// - Parameter info: The glyph information to apply.
/// - Parameter changeName: Whether to adopt the name from the glyph information.
/// - Parameter changeUnicode: Whether to adopt the Unicode values from the glyph information.
- (void)applyGlyphInfo:(GSGlyphInfo *)info changeName:(BOOL)changeName changeUnicode:(BOOL)changeUnicode;

/// Applies a record from the Glyph Info Database without normal name and Unicode change handling.
///
/// Glyph info stored as glyph-local overrides is preserved.
/// Use this while constructing a glyph that is not yet part of a font.
///
/// - Parameter info: The glyph information to apply.
/// - Parameter changeName: Whether to adopt the name from the glyph information.
/// - Parameter changeUnicode: Whether to adopt the Unicode values from the glyph information.
- (void)applyGlyphInfoFast:(GSGlyphInfo *)info changeName:(BOOL)changeName changeUnicode:(BOOL)changeUnicode;

@end

NS_ASSUME_NONNULL_END
