//
//  GSFont.h
//  Glyphs
//
//  Created by Georg Seifert on 21.10.05.
//  Copyright 2005 schriftgestaltung.de. All rights reserved.
//

@class GSGlyph;
@class GSLayer;
@class GSDocument;
@class GSFontMaster;
@class GSInstance;
@class GSFeature;
@class GSClass;
@class GSFeaturePrefix;

@class GSCustomParameter;
@class GSGlyphsInfo;

@class GSFontInfoProperty;
@class GSFontInfoValue;
@class GSMetricValue;
#ifndef GLYPHS_VIEWER
@class GSGlyphInfo;
@class GSFontInfoValueLocalized;
#endif
#ifndef GLYPHS_LITE
@class COFont;
#endif

#import <GlyphsCore/GSAxis.h>
#import <GlyphsCore/GSBase.h>
#import <GlyphsCore/GSContainerProtocol.h>
#import <GlyphsCore/GSMetric.h>
#import <GlyphsCore/GSUserDataProtocol.h>
#import <GlyphsCore/MGOrderedDictionary.h>
#ifdef GLYPHS_VIEWER
#import <GlyphsCore/CFOldStylePList.h>
#endif

NS_ASSUME_NONNULL_BEGIN

extern NSString *GSPropertyNameFamilyNamesKey;
extern NSString *GSPropertyNameDesignersKey;
extern NSString *GSPropertyNameDesignerURLKey;
extern NSString *GSPropertyNameManufacturersKey;
extern NSString *GSPropertyNameManufacturerURLKey;
extern NSString *GSPropertyNameCopyrightsKey;
extern NSString *GSPropertyNameVersionStringKey;
extern NSString *GSPropertyNameVersionKey;
extern NSString *GSPropertyNameVendorIDKey;
extern NSString *GSPropertyNameUniqueIDKey;
extern NSString *GSPropertyNameLicensesKey;
extern NSString *GSPropertyNameLicenseURLKey;
extern NSString *GSPropertyNameTrademarksKey;
extern NSString *GSPropertyNameDescriptionsKey;
extern NSString *GSPropertyNameSampleTextsKey;
extern NSString *GSPropertyNamePostscriptFullNameKey;	// old key
extern NSString *GSPropertyNamePostscriptFullNamesKey;	// new localized
extern NSString *GSPropertyNamePostscriptFontNameKey;
extern NSString *GSPropertyNameVariablePostscriptFontNameKey;
extern NSString *GSPropertyNameCompatibleFullNamesKey;
extern NSString *GSPropertyNameStyleNamesKey;
extern NSString *GSPropertyNameStyleMapFamilyNamesKey;
extern NSString *GSPropertyNameStyleMapStyleNamesKey;
extern NSString *GSPropertyNamePreferredFamilyNamesKey;
extern NSString *GSPropertyNamePreferredSubfamilyNamesKey;
extern NSString *GSPropertyNameVariableStyleNamesKey;
extern NSString *GSPropertyNameWWSFamilyNameKey;
extern NSString *GSPropertyNameWWSSubfamilyNameKey;
extern NSString *GSPropertyNameVariationsPostScriptNamePrefixKey;
extern NSString *GSPropertyNameFontTypeKey;

extern NSString *GSFontTypeDefaultKey;
extern NSString *GSFontTypeVariableKey;
extern NSString *GSFontTypeLayerFontKey;
extern NSString *GSFontTypeIconSetKey;

extern NSString *GSFontFilePathKey;

extern UTF32Char FirstUnencoded;
extern UTF32Char LastUnencoded;

typedef NS_ENUM(int8_t, GSFontType) {
	GSFontTypeDefault = 0,
	GSFontTypeVariable = 1,
	GSFontTypeLayerFont = 2,
	GSFontTypeIconSet = 3,
};

NSInteger compareKerning(NSString *obj1, NSString *obj2, void *context);
/**
 This class defines the font object.

 Font info properties, that have a user interface, have proper accessors, everything else is stored in the custom parameters
 */
@interface GSFont : NSObject <NSCoding, NSCopying, GSContainerProtocol, GSUserDataProtocol> {
	NSMutableArray<GSGlyph *> *_glyphs;
#ifdef QUICKLOOK
	NSArray<NSString *> *_glyphFiles;
#endif
	uint32_t _unitsPerEm;
	NSDate *_date;
	NSUInteger _versionMajor;
	NSUInteger _versionMinor;
	NSMutableArray *_fontMasters;
	NSMutableArray *_instances;
	NSMutableDictionary *_userData;
	NSMutableDictionary *_charsCache;
	UTF32Char _lastChar;
	MGOrderedDictionary<NSString *, MGOrderedDictionary *> *_kerningLTR;
	MGOrderedDictionary<NSString *, MGOrderedDictionary *> *_kerningRTL;
	MGOrderedDictionary<NSString *, MGOrderedDictionary *> *_kerningContext;
	MGOrderedDictionary<NSString *, MGOrderedDictionary *> *_kerningVertical;
	uint32_t _gridMain;
	uint32_t _gridSubDivision;
	CGFloat _keyboardIncrement;
	CGFloat _keyboardIncrementBig;
	CGFloat _keyboardIncrementHuge;
	BOOL _previewRemoveOverlap;
	BOOL _disablesNiceNames;
	BOOL _disablesAutomaticAlignment;
	BOOL _keepAlternatesTogether;
	BOOL _snapToObjects;
	NSMutableDictionary *_name2Glyph;
	NSMutableArray *_glyphDictArray;
	NSMutableArray<GSFeature *> *_features;
	NSMutableArray<GSClass *> *_classes;
	NSMutableArray<GSFeaturePrefix *> *_featurePrefixes;
#ifndef GLYPHS_LITE
	NSString *_tempOTFFont;
	COFont *_compositorFont;
#endif
	BOOL _disabledChanges;
	NSMutableSet *_disabledChangeKeys;
	NSDate *_lastAskedForImage;

#pragma GSAutoCodeStart ivars

	NSString *_fontName;
	NSMutableArray<GSAxis *> *_axes;
	NSMutableArray<GSFontInfoProperty *> *_properties;
	NSMutableArray<GSCustomParameter *> *_customParameters;
	NSString *_note;
#pragma GSAutoCodeEnd ivars

#ifdef GLYPHS_VIEWER
  @public
	GSPlistParseInfo _pInfo;
#endif
}

#ifndef GLYPHS_VIEWER
/** Returns the content of the object to store it in pList.

 This is used to store the data in the .glyphs file.
 @param format the version of the dict
 */
- (nullable NSDictionary *)propertyListValueFormat:(GSFormatVersion)format;
#endif

/// unitsPerEm (UPM).
@property (assign, nonatomic) uint32_t unitsPerEm;

#ifdef GLYPHS_LITE
@property (strong, nonatomic, nullable) NSString *license;
#endif

/// versionMajor
@property (assign, nonatomic) NSUInteger versionMajor;

/// versionMinor
@property (assign, nonatomic) NSUInteger versionMinor;

/// The font date
@property (strong, nonatomic) NSDate *date;

#ifndef GLYPHS_VIEWER
- (BOOL)applyGlyphSetParameters:(GSInstance * _Nonnull)instance error:(NSError **)error;
#endif

@property (nonatomic) BOOL ignoreCompatibilityWarning;

#pragma mark TempData
/**
 a  dictionary that stores data. It will not be written to disk.
 */
@property (nonatomic, strong, nullable) NSDictionary *tempData;

/**
 Adds key/value to tempData. Pass nil as value to remove previous set data

 @param value and object or nil
 @param key the key
 */
- (void)setTempData:(nullable id)value forKey:(nonnull NSString *)key;

/**
 return value for key in tempData

 @param key the key
 @return a value or nil
 */
- (nullable id)tempDataForKey:(nonnull NSString *)key;

#pragma mark -
/** disablesNiceNames

 This is to prevent the automatic glyph name substitution.
 Set it to YES before you do big changes. Make sure to disable it after you are finished.
 */
@property BOOL disablesNiceNames;

/** Disables automatic alignment of components */
@property (nonatomic) BOOL disablesAutomaticAlignment;

/** Keeps alternated glyphs next to the base glyph */
@property (nonatomic) BOOL keepAlternatesTogether;

@property (nonatomic, strong, nullable) NSMutableSet *disabledChangeKeys;

#pragma mark -
/// @name Creating and Initializing a GSFont object

/** initializes a font with a dictionary loaded from a pList.

 @param fontDict A dictionary
 @param error If there is a error it contains an NSError object
 */
- (nullable instancetype)initWithDict:(NSDictionary *)fontDict error:(out NSError **)error;

/**
 Initializes a font with the contents of the location specified by a given URL.

 @param fileURL the location of the file
 @param error If there is a error it contains an NSError object
 @return the GSFont object or nil
 */
- (nullable instancetype)initWithURL:(NSURL *)fileURL error:(out NSError **)error;

- (BOOL)postRead:(out NSError **)error;
- (BOOL)preWrite:(out NSError **)error;

- (void)postProcess;

/// @name Font Methods

#ifndef GLYPHS_VIEWER
#ifndef LIBCORE
#ifndef GLYPHS_LITE

/** Scale the hole font.

 @param scale Multiplier for scale the font (glyphs, kerning and metrics)
 */
- (void)scaleBy:(CGFloat)scale;

#endif
#endif
#endif

#pragma mark Font Type

@property (nonatomic) GSFontType fontType;

+ (NSString *)fontTypeKeyForType:(GSFontType)fontType;

+ (GSFontType)fontTypeForTypeKey:(NSString *)fontTypeKey;

#pragma mark Axes
/// @name Axes

- (nullable GSAxis *)axisForName:(NSString *)axisName;

- (nullable GSAxis *)axisForId:(NSString *)axisId;

- (nullable GSAxis *)axisForTag:(NSString *)axisTag;

#ifndef GLYPHS_LITE
- (NSMutableArray<GSAxis *> *)legacyAxes;

+ (NSArray<GSMetricValue *> *)axesPositionsFromAxes:(NSArray<GSAxis *> *)fontAxes master:(GSFontMaster *)master;

+ (CGFloat *)axesValueListFromAxes:(NSArray<GSAxis *> *)axes axesValues:(GSAxisValues *)axesValues;

+ (void)axesValueListFromAxes:(NSArray<GSAxis *> *)axes axesValues:(GSAxisValues *)axesValues intoList:(CGFloat *)axesValueList;

+ (GSAxisValues *)axesValuesFromAxes:(NSArray<GSAxis *> *)axes axesValuesList:(CGFloat *)axesValueList;

// used for compiling feature variations form feature code
- (nullable NSDictionary *)variationAxesRanges:(nullable GSFontMaster *)defaultMaster;

// a list of axes values for each axis
- (NSMutableDictionary *)axesValueSteps:(NSArray *)masterIds glyph:(nullable GSGlyph *)glyph;

#endif

- (GSFontMaster *)defaultFontMaster:(nullable GSInstance *)instance;

#ifndef GLYPHS_LITE
- (BOOL)masterRangesInternMin:(CGFloat *)internMin internDefault:(nullable CGFloat *)internDefault internMax:(CGFloat *)internMax externMin:(CGFloat *)externMin externDefault:(nullable CGFloat *)externDefault externMax:(CGFloat *)externMax mastersIntern:(CGFloat *_Nullable *_Nullable)mastersIntern mastersExtern:(CGFloat *_Nullable *_Nullable)mastersExtern defaultMaster:(nullable GSFontMaster *)defaultMaster error:(out NSError **)error;

+ (BOOL)masterRangesFor:(NSArray <GSAxis *>*)axes masters:(NSArray<GSFontMaster *>*)masters customParameters:(NSArray <GSCustomParameter *>*)customParameters internMin:(CGFloat *)internMin internDefault:(nullable CGFloat *)internDefault internMax:(CGFloat *)internMax externMin:(CGFloat *)externMin externDefault:(nullable CGFloat *)externDefault externMax:(CGFloat *)externMax mastersIntern:(CGFloat *_Nullable*_Nullable)mastersIntern mastersExtern:(CGFloat *_Nullable*_Nullable)mastersExtern defaultMaster:(nullable GSFontMaster *)defaultMaster error:(out NSError **)error;

#endif

/// @name Metrics

@property (nullable, strong, nonatomic) NSArray<GSMetric *> *metrics;

@property (nullable, readonly, nonatomic) id metricsContent; // to support KVO;
- (NSUInteger)countOfMetrics;
- (nullable GSMetric *)objectInMetricsAtIndex:(NSUInteger)idx;
- (void)removeObjectFromMetrics:(GSMetric *)metric;
- (void)addMetric:(GSMetric *)metric;

- (nullable GSMetric *)objectInMetricsWithName:(NSString *)name;
- (nullable GSMetric *)objectInMetricsWithType:(GSMetricsType)type withName:(NSString *)name;
- (nullable GSMetric *)objectInMetricsWithType:(GSMetricsType)type withName:(NSString *)name filter:(nullable NSString *)filter;

/// @name Stems

@property (nullable, strong, nonatomic) NSArray<GSMetric *> *stems;
- (NSUInteger)countOfStems;
- (nullable GSMetric *)objectInStemsAtIndex:(NSUInteger)idx;
- (void)removeObjectFromStems:(GSMetric *)stem;
- (void)addStem:(GSMetric *)stem;
- (nullable GSMetric *)stemForId:(NSString *)stemId;
- (nullable GSMetric *)stemForName:(NSString *)name;

/// @name Numbers

@property (nullable, strong, nonatomic) NSArray<GSMetric *> *numbers;
- (NSUInteger)countOfNumbers;
- (nullable GSMetric *)objectInNumbersAtIndex:(NSUInteger)idx;
- (void)removeObjectFromNumbers:(GSMetric *)number;
- (void)addNumber:(GSMetric *)number;
- (nullable GSMetric *)numberForId:(NSString *)name;
- (nullable GSMetric *)numberForName:(NSString *)name;

/// @name Glyphs

/// The array of GSGlyph objects
@property (strong, nonatomic) NSArray<GSGlyph *> *glyphs;

/** allGlyphs
 All glyphs including the imported glyphs.
 */
@property (strong, nonatomic) NSArray<GSGlyph *> *allGlyphs;

- (NSUInteger)count;

/** The count of glyphs in the font */
- (NSUInteger)countOfGlyphs;

/** The glyph object located at index.

 Checks for valid index and returns nil if index is to high.

 @param idx An index within the bounds of the the glyphs array.
 @return a GSGlyph object.
 */
- (nullable GSGlyph *)glyphAtIndex:(NSInteger)idx;

/** Returns the index of the glyph.

 @param glyph The Glyph you are looking for
 @return The index of the glyph or NSNotFound if not found
 */
- (NSInteger)indexOfGlyph:(GSGlyph *)glyph;

@property (nonatomic, readonly) NSDictionary *charsCache;

/** If you changed the glyphs array yourself, call that method to reset some chances. */
- (void)resetCache;

/** Returns the GSGlyph with this name.

 @warning This is a bit slow.

 @param name the name of the glyph.
 @return a GSGlyph object.
 */
- (nullable GSGlyph *)glyphForName:(NSString *)name;

- (nullable GSGlyph *)localGlyphForName:(NSString *)name;

#ifndef GLYPHS_LITE
/**
 A list of glyph names matching query

 @param query This can be a name containing wildcards ("a.*") or a query ("script=arabic")
 @param error if something goes wrong, it contains an error on return
 @return a list of glyph names or nil
 */
- (nullable NSArray *)glyphNamesForWildcard:(NSString *)query contextLabel:(NSString *)contextLabel error:(out NSError **)error;

- (nullable NSSet *)expandWildcardsInNameList:(NSArray *)nameList contextLabel:(NSString *)contextLabel error:(out NSError **)error;

#ifndef LIBCORE
- (nullable NSString *)baseName:(NSString *)name forWildCard:(NSString *)wild;
#endif

- (void)prepareName2Glyph;
#endif

- (GSGlyph *)glyphForNameFast:(NSString *)name;

/** A list of glyph names

 @return A list of glyph names
 */
- (NSArray *)glyphNames;

- (NSArray *)exportingGlyphNames;

/** Returns the GSGlyph with this this Unicode.

 @param unicode the unicode as a hex string ('004C')
 @return a GSGlyph object or nil if not found.
 @see resetCache If you changed some glyphs and this method returns wrong results, call resetCache
 */
- (nullable GSGlyph *)glyphForUnicode:(NSString *)unicode;

- (nullable GSGlyph *)glyphForUnicodeFast:(NSString *)unicode;

/** Returns the GSGlyph with this this Unicode.

 @param unicodes a list of unicodes as hex strings ('004C')
 @return a GSGlyph object or nil if not found.
 @see resetCache If you changed some glyphs and this method returns wrong results, call resetCache
 */
- (nullable GSGlyph *)glyphForUnicodes:(NSOrderedSet *)unicodes;
- (nullable GSGlyph *)localGlyphForUnicodes:(NSOrderedSet *)unicodes;

- (nullable GSGlyph *)localGlyphForUnicodeFast:(NSString *)unicode;

- (void)glyphHasChangedName:(GSGlyph *)glyph oldName:(NSString *)oldName;

#ifndef GLYPHS_VIEWER
- (GSGlyph *)newGlyphWithName:(NSString *)glyphName;

/** Adds a new glyph with this glyphName to the font

 @param glyphName  The new glyph name
 @param changeName If changeName is yes, the glyphName will be converted to nice-name, otherwise not.

 @return The new glyph.
 */
- (GSGlyph *)newGlyphWithName:(NSString *)glyphName changeName:(BOOL)changeName;

- (void)makeSaveGlyphInfo:(GSGlyph *)glyph;

- (void)calculateDefaultWidth:(GSGlyph *)glyph;

/** Calculates a names that is unique for the font

 @param glyph The Glyph

 @return The glyph name with a .0XX suffix if the name is already in use by another glyph
 */
- (NSString *)saveNameForGlyph:(GSGlyph *)glyph;

- (nullable NSString *)saveSuffixForGlyph:(GSGlyph *)glyph;
/** Calculates a names that is unique for the font

 @param glyphName The glyph name

 @return The glyph name with a .0XX suffix if the name is already in use by another glyph
 */
- (NSString *)saveNameForName:(NSString *)glyphName;

#endif

/** Returns the GSGlyph with this ID.

 @warning This is a bit slow.

 @param ID the ID of the glyph.
 @return a GSGlyph object.
 */
- (nullable GSGlyph *)glyphForId:(NSString *)ID;

/** Returns all glyphs for the names.

 @param glyphNames a list a names
 @return a list of glyphs or nil
 */
- (nullable NSArray<GSGlyph*> *)glyphsForNames:(NSArray <NSString*> *)glyphNames;

#ifndef GLYPHS_VIEWER
/** Tests if all the glyphs are present and set to export

 @param glyphNames A array of glyph names
 @return YES if all glyphs will end up in an exported font.
 @see filterKeepGlyphs:
 @see filterGlyphs:
 */
- (BOOL)keepsGlyphs:(NSArray<NSString *> *)glyphNames;

/** Tests if all the glyphs are present and set to export

 @param unicodes A array of unicodes
 @return YES if all glyphs will end up in an exported font.
 @see filterKeepGlyphs:
 @see filterGlyphs:
 */
- (BOOL)keepsGlyphsCode:(NSArray<NSString *> *)unicodes;
#endif
/** Returns all glyph names that are present and set to export

 @param glyphNames A array of glyph names
 @return A list of exporting glyphs
 @see keepsGlyphs:
 @see filterGlyphs:
 */
- (nullable NSArray *)filterKeepGlyphs:(NSArray<NSString *> *)glyphNames;

- (nullable NSArray *)filterKeepGlyphsCodes:(NSArray<NSString *> *)unicodes;
/** Returns all glyph names that are present and set to export

 @param glyphNames A array of glyph names
 @return A list of all glyphs that are in the font
 @see keepsGlyphs:
 @see filterKeepGlyphs:
 */
- (nullable NSArray <NSString *> *)filterGlyphs:(NSArray<NSString *> *)glyphNames;
#ifndef GLYPHS_VIEWER
- (nullable NSArray *)filterGlyphsWithInfos:(NSArray<GSGlyphInfo *> *)glyphInfos;

- (NSArray *)glyphsContainingComponentWithName:(NSString *)glyphName masterId:(NSString *)masterID;
#endif

/** Returns the glyph with the chars unicode.

 @param aChar A (unicode) char.
 @return a GSGlyph object
 @see characterForGlyph:
 */
- (nullable GSGlyph *)glyphForCharacter:(UTF32Char)aChar;

- (nullable GSGlyph *)glyphFromCharsCacheForUnicode:(NSString *)unicode;

- (nullable GSGlyph *)glyphFromCharsCacheForChar:(UTF32Char)aChar;

- (nullable GSGlyph *)glyphFromCharsCacheForCharFast:(UTF32Char)aChar;

- (void)preloadCharCache;

/** Returns a UTF32Char for the glyph.

 It uses the unicode to find the char value. For unencoded glyphs it returns a cached PUA value.

 @param glyph a GSGlyph object
 @return a UTF32Char
 @sa glyphForCharacter:
 */
- (UTF32Char)characterForGlyph:(GSGlyph *)glyph;

#ifndef GLYPHS_VIEWER

- (NSSet *)componentGlyphNamesForGlyph:(GSGlyph *)glyph;

/** Adds the Glyph object to the font.

 @param glyph A GSGlyph object.
 */
- (void)addGlyph:(GSGlyph *)glyph;

- (void)addGlyphFast:(GSGlyph *)glyph;

/** Adds the Glyphs object to the font.

 @param glyphs A NSArray of GSGlyph objects.
 */
- (void)addGlyphsFromArray:(NSArray<GSGlyph *> *)glyphs;

/** Removes the Glyph from the font

 @param glyph A GSGlyph to remove from the font.
 */
- (void)removeGlyph:(GSGlyph *)glyph;

/** Removes the Glyphs from the font

 @param glyphs A NSArray of GSGlyph to remove from the font.
 */
- (void)removeGlyphs:(NSArray<GSGlyph *> *)glyphs;

#endif

#ifndef LIBCORE
/** Is called if the there are changes. */
- (void)sortGlyphs;
#endif

- (void)sortGlyphs:(NSMutableArray *)glyphs withList:(nullable NSArray *)nameList;

/** Triggers the sorting of kerning */
- (void)sortKerning;

/// Sort Metrics with values from first master
- (void)sortMetrics;

- (void)elementDidChange:(id)element;

/** The panose value for the font */
- (nullable NSMutableArray *)panose;

#pragma mark masters

/// @name Masters

/// An array of GSFontMaster objects
@property (strong, nonatomic) NSArray<GSFontMaster *> *fontMasters;

@property (strong, nonatomic) NSArray<GSFontMaster *> *importedFontMasters;

@property (strong, nonatomic) NSArray<GSFont *> *importedFonts;

@property (strong, nonatomic) NSArray<GSGlyph *> *importedGlyphs;
/** The count of masters in the font.

 @return The number of layers currently in the font.
 */
- (NSInteger)countOfFontMasters;

/** The master located at index

 @param idx An index
 @return A GSFontMaster instance or nil if index is out of bounds
 */
- (nullable GSFontMaster *)fontMasterAtIndex:(NSInteger)idx;

- (NSUInteger)indexOfFontMaster:(GSFontMaster *)master;
/** Returns the fontMaster with this id

 @param id The ID of the font master. This is supposed to be a Unique id
 @return A GSFontMaster instance.
 */
- (nullable GSFontMaster *)fontMasterForId:(nullable NSString *)id;

#ifndef GLYPHS_VIEWER
/** Inserts the fontMaster at idx

 @param fontMaster The master to add to the font
 @param idx The index to insert FontMaster.
 */
- (void)insertFontMaster:(GSFontMaster *)fontMaster atIndex:(NSUInteger)idx;

/** Adds the fontMaster to the font

 @param fontMaster The master to add.
 */
- (void)addFontMaster:(GSFontMaster *)fontMaster;

/** Removes the fontMaster from the font

 @param fontMaster The master to remove.
 */
- (void)removeFontMaster:(GSFontMaster *)fontMaster;

- (GSFontMaster *)addFontMasterAndContent:(GSFontMaster *)fontMaster;

- (void)removeFontMasterAndContent:(GSFontMaster *)fontMaster;

- (void)replaceFontMasterAtIndex:(NSUInteger)idx withFontMaster:(GSFontMaster *)fontMaster;

#ifndef GLYPHS_LITE
- (void)copyGlyphs:(nonnull GSFont *)sourceFont sourceFontMasterID:(nonnull NSString *)sourceFontMasterID targetFontMasterID:(nonnull NSString *)targetFontMasterID addMissing:(BOOL)addMissing;

- (void)copyInfoFrom:(GSFont *)sourceFont sourceFontMasterID:(NSString *)sourceFontMasterID targetFontMasterID:(NSString *)targetFontMasterID;

- (GSFontMaster *)addFontAsNewMaster:(GSFontMaster *)master;
#endif
#endif
#pragma mark imported Masters

@property (readonly) NSArray *allMasters;
- (NSUInteger)countOfAllMasters;
- (nullable GSFontMaster *)allMasterAtIndex:(NSInteger)idx;

- (nullable GSFontMaster *)masterNearestToPosition:(CGFloat *)position;

- (nullable GSFontMaster *)masterNearestToPosition:(CGFloat *)position glyph:(nullable GSGlyph *)glyph;

- (GSInstance *)instanceNearestToPosition:(CGFloat *)position distance:(nullable CGFloat *)distance;

- (BOOL)reloadLinkedFonts:(out NSError **)error;
#pragma mark metrics
#ifndef GLYPHS_VIEWER
/**
 Recalculate the LSB and RSB for all glyph

 This will not apply the metrics keys.
 */
- (void)updateMetrics;

#endif
#pragma mark instances

/// @name Instances

/// An array of GSInstance objects. This define export settings for interpolation and naming.
@property (strong, nonatomic) NSArray<GSInstance *> *instances;

/** The count of the Instances

 @return The number of Instances currently in the Font.
 */
- (NSUInteger)countOfInstances;

/** The Instance at index

 @param idx The index of the instance.
 @return The Instance located at _index_.
 */
- (nullable GSInstance *)objectInInstancesAtIndex:(NSUInteger)idx;

#ifndef GLYPHS_VIEWER

/** Inserts the instance at Index

 @param instance The instance to insert.
 @param idx The _index_ at what to insert the _instance_.
 */
- (void)insertObject:(GSInstance *)instance inInstancesAtIndex:(NSUInteger)idx;
- (void)insertInstance:(GSInstance *)instance atIndex:(NSUInteger)idx;

/** Adds the Instance to the font

 @param instance The Instance to add to the font.
 */
- (void)addInstance:(GSInstance *)instance;
#endif

/**
 this returns a lists of instance with unique instances only for glyph.layerGroups
 */
- (NSArray *)instancesUnique;

#ifndef GLYPHS_VIEWER
- (void)removeInstance:(GSInstance *)instance;

- (void)removeInstances:(NSArray *)instances;
/** Removes the Instance at Index.

 @param idx The of the Instance to be removed.
 */
- (void)removeObjectFromInstancesAtIndex:(NSUInteger)idx;

- (void)replaceObjectInInstancesAtIndex:(NSUInteger)idx withObject:(GSInstance *)instance;

#ifndef GLYPHS_LITE
- (nullable GSFontMaster *)interpolateFontMaster:(GSInstance *)instance scale:(CGFloat)scale thin:(BOOL)thin error:(out NSError **)error;
#endif

#ifndef LIBCORE
/** Generates an instance

 It returns a new GSFont object with one master interpolated all glyphs/layers according to the settings in Instance.

 @param instance The Instance to use for interpolation.
 @param error if there is a problem, it returns an NSError object (by reference) that contains details.
 @return The interpolated font, or nil if something went wrong.
 */

- (nullable GSFont *)generateInstance:(GSInstance *)instance error:(out NSError **)error;

#ifndef GLYPHS_LITE

// TODO: this is half of a copy of the above method. This needs some refactoring.
- (nullable GSFont *)generateVariable:(GSInstance *)instance error:(out NSError **)error;
#endif
#endif
#endif
#pragma mark kerning

/**
 The master that will supply the tt/ps hints

 @param master the master that should get the hints
 */
- (nonnull NSString *)masterIDforHints:(nullable GSFontMaster *)master;

/// @name Kerning

- (MGOrderedDictionary *)kerningForDirection:(GSWritingDirection)direction;

- (NSString *)masterIDforMetrics:(NSString *)masterID;

- (NSString *)masterIDforMetrics:(NSString *)masterID hasLink:(nullable BOOL *)hasLink;

- (MGOrderedDictionary *)masterKerning:(NSString *)masterID direction:(GSWritingDirection)direction;

/** the Kerning of the Font

 1) A Dict for each FontMaster (FontMaster id as key)
 2) The Dict contains an entry for each glyph (the glyphID or GroupName (@MMK_L_XXX) is used as key)
 3) These entries hold the values: glyphID or GroupName (@MMK_R_XXX) as key, kerning as value.
 */
@property (strong, nonatomic) MGOrderedDictionary<NSString *, MGOrderedDictionary *> *kerningLTR;
@property (strong, nonatomic) MGOrderedDictionary<NSString *, MGOrderedDictionary *> *kerningRTL;
@property (strong, nonatomic) MGOrderedDictionary<NSString *, MGOrderedDictionary *> *kerningContext;

/** the vertical Kerning of the Font

 1) A Dict for each FontMaster (FontMaster id as key)
 2) The Dict contains an entry for each glyph (the glyphID or GroupName (@MMK_L_XXX) is used as key)
 3) These entries hold the values: glyphID or GroupName (@MMK_R_XXX) as key, kerning as value.
 */
@property (strong, nonatomic) MGOrderedDictionary<NSString *, MGOrderedDictionary *> *kerningVertical;

#ifndef GLYPHS_VIEWER

/** Compresses the kerning

 if a GSGlyph has a Kerning Group and Direct Kerning, the Kerning is changed to Class Kerning.
 */
- (void)compressKerningForDirection:(GSWritingDirection)direction;

- (void)cleanUpKerningForDirection:(GSWritingDirection)direction;

- (void)migrateRTLKerning;

- (nullable MGOrderedDictionary<NSString *,MGOrderedDictionary *> *)migrateRTLKerningDict:(NSMutableDictionary *)kerningDict doClasses:(BOOL)doClasses;

- (nullable MGOrderedDictionary *)backportRTLKerning;
#endif

- (void)setKerning:(MGOrderedDictionary *)kerning forMaster:(NSString *)fontMasterID direction:(GSWritingDirection)direction;

- (void)addKerning:(MGOrderedDictionary *)kerning forMaster:(NSString *)fontMasterID direction:(GSWritingDirection)direction;

- (CGFloat)kerningForFontMasterID:(NSString *)fontMasterID firstGlyph:(GSGlyph *)firstGlyph secondGlyph:(GSGlyph *)secondGlyph direction:(GSWritingDirection)direction;

- (CGFloat)kerningForFontMasterDict:(NSDictionary *)masterKerning firstGlyph:(GSGlyph *)firstGlyph secondGlyph:(GSGlyph *)secondGlyph direction:(GSWritingDirection)direction;

/** Returns a kerning value

 @param fontMasterID The Master id
 @param leftKey either a glyph id or a glyph group (@MM_L_XXX)
 @param rightKey either a glyph id or a glyph group (@MM_R_XXX)
 @return the kerning value, or NSNotFound if there is no pair
 */

- (CGFloat)kerningForFontMasterID:(id)fontMasterID leftKey:(id)leftKey rightKey:(id)rightKey direction:(GSWritingDirection)direction;

#ifndef GLYPHS_VIEWER
/** adds a kerning value

 @param fontMasterID The Master id
 @param leftKey either a glyph id or a glyph group (@MM_L_XXX)
 @param rightKey either a glyph id or a glyph group (@MM_R_XXX)
 @param value the kerning value
 */

- (void)setKerningForFontMasterID:(id)fontMasterID leftKey:(id)leftKey rightKey:(id)rightKey value:(CGFloat)value direction:(GSWritingDirection)direction;

/** removes a kerning value

 @param fontMasterID The Master id
 @param leftKey either a glyph id or a glyph group (@MM_L_XXX)
 @param rightKey either a glyph id or a glyph group (@MM_R_XXX)
 */

- (void)removeKerningForFontMasterID:(NSString *)fontMasterID leftKey:(NSString *)leftKey rightKey:(NSString *)rightKey direction:(GSWritingDirection)direction;

- (void)setContextKerningForFontMasterID:(NSString *)fontMasterID leftKey:(NSString *)leftKey rightKey:(NSString *)rightKey value:(CGFloat)value before:(NSString *)beforeKey after:(NSString *)afterKey;

- (void)removeContextKerningForFontMasterID:(NSString *)fontMasterID leftKey:(NSString *)leftKey rightKey:(NSString *)rightKey before:(NSString *)beforeKey after:(id)afterKey;
#endif

#pragma mark features

/// @name Features

/// An array of GSFeature objects.
@property (strong, nonatomic) NSArray<GSFeature *> *features;

#ifndef GLYPHS_VIEWER
/** The count of the features

 @return The number of features in the Font.
 */
- (NSUInteger)countOfFeatures;

/** Returns the index of feature in features

 @param feature the object
 @return the index of the object
*/
- (NSUInteger)indexOfFeature:(GSFeature *)feature;


/** The feature at index

 @param idx The index of the feature
 @return The feature located at idx.
 */
- (nullable GSFeature *)objectInFeaturesAtIndex:(NSUInteger)idx;

/// Inserts the Feature at idx
- (void)insertObject:(GSFeature *)feature inFeaturesAtIndex:(NSUInteger)idx;

/// Removes the Feature at idx
- (void)removeObjectFromFeaturesAtIndex:(NSUInteger)idx;

- (void)replaceObjectInFeaturesAtIndex:(NSUInteger)idx withObject:(GSFeature *)feature;

//- (void)replaceFeaturesAtIndexes:(NSIndexSet *)indexes withFeatures:(NSArray *)featureArray;

/// Adds the Feature
- (void)addFeature:(GSFeature *)feature;

- (void)removeFeature:(GSFeature *)feature;

#ifndef GLYPHS_LITE
/** Returns the feature with the name or tag.

 @param tag The feature tag (like "smcp")
 */
- (nullable GSFeature *)featureForTag:(NSString *)tag;

- (nullable GSFeature *)automaticFeatureForTag:(NSString *)tag;


- (BOOL)updateFeatures:(NSError **)error;

- (BOOL)importFeatures:(NSString *)featuresString error:(out NSError **)error;

#endif
#endif
#pragma mark Classes

/// @name Classes

/// An array of GSClasse objects
@property (strong, nonatomic) NSArray<GSClass *> *classes;

#ifndef GLYPHS_VIEWER
- (NSMutableArray<GSClass *> *)mutableClasses;

/// The count of the classes
- (NSUInteger)countOfClasses;

- (nullable GSClass *)objectInClassesAtIndex:(NSUInteger)index;

/** Returns the class with the name.

 @param tag The class name.
 */
- (nullable GSClass *)classForTag:(NSString *)tag;

/** Adds a class to the font

 @param aClass the Class
 */
- (void)addClass:(GSClass *)aClass;

/** Insert the Class at idx in the font

 @param aClass the class
 @param idx the index
 */
- (void)insertObject:(GSClass *)aClass inClassesAtIndex:(NSUInteger)idx;

/** Remove the class at idx from the font

 @param idx the index
 */
- (void)removeObjectFromClassesAtIndex:(NSUInteger)idx;

/** Removes the class from the font

 @param aClass the class
 */
- (void)removeClass:(GSClass *)aClass;

/** Replaces the the class a idx with Class

 @param idx the index
 @param aClass the class
 */
- (void)replaceObjectInClassesAtIndex:(NSUInteger)idx withObject:(GSClass *)aClass;

/** Convenient method to add a class with the Text

 @param text the class in FDK syntax, e.g. "@myClass = [A B];"
 */
- (void)addClassFromCode:(NSString *)text;
#endif
#pragma mark FeaturePrefixes

/// @name FeaturePrefixes

/**
 An array of GSFeaturePrefix objects that contain additional lookups
 */
@property (nonatomic, strong) NSArray<GSFeaturePrefix *> *featurePrefixes;

#ifndef GLYPHS_VIEWER
/** Adds the Prefix to the font

 @param thePrefix the prefix
 */
- (void)addFeaturePrefix:(GSClass *)thePrefix;

/** the count of the Prefixes in the font */
- (NSUInteger)countOfFeaturePrefixes;

- (nullable GSFeaturePrefix *)objectInFeaturePrefixesAtIndex:(NSUInteger)idx;

/** Returns the Prefix with the name.

 @param tag The prefix name.
 */
- (nullable GSFeaturePrefix *)featurePrefixForTag:(NSString *)tag;

/** Insert the Prefix at idx in the font

 @param thePrefix the prefix
 @param idx the idx
 */
- (void)insertObject:(GSFeaturePrefix *)thePrefix inFeaturePrefixesAtIndex:(NSUInteger)idx;

/** Remove the Prefix at idx from the font

 @param thePrefix the prefix
 */
- (void)removeFeaturePrefix:(GSClass *)thePrefix;

#pragma mark display
/** Converts a string that contains slash separated glyph names in a regular unicode string

 @param string A String containing slash separated glyph names
 @return A UTF-16 string. For it will assign a cached PUA codes for unencoded glyphs
 */
- (NSString *)charStringFromDisplayString:(NSString *)string;

/** Delays redrawing and updates.

 Will record the changes and update once in `enableUpdateInterface`. If you don’t need updates, use `stopUpdateInterface`

 @see stopUpdateInterface
 @warning Always call enableUpdateInterface afterwards
 */
- (void)disableUpdateInterface;

/** Disable redrawing and updates completely.

 Changes will not trigger an update. Only use this carefully and call enableUpdateInterface if you need future updates.

 @see disableUpdateInterface
 @warning Always call enableUpdateInterface afterwards
 */
- (void)stopUpdateInterface;

/** Reenables redrawing and updates.

 This only has an effect if disableUpdateInterface was called before
 */
- (void)enableUpdateInterface;

- (void)enableFutureUpdates;
/** Check if the updating is enabled

 @return NO if disableUpdateInterface was called
 */
- (BOOL)isUpdateInterfaceEnabled;

#endif

- (nullable GSGlyphsInfo *)glyphsInfo;

#pragma mark Metrics

/** The size of the grid.

 If it is `0`, all values are stored as floats. `1` and above will ALWAYS round the coordinates.

 @see gridLength
 */
@property (nonatomic, assign) uint32_t gridMain;

/** The subdivision of the grid.

 Divides the grid.

 @see gridLength
 */
@property (nonatomic, assign) uint32_t gridSubDivision;

/** The effective grid width.

 Calculated by Grid / Subdivision

 @return The effective size of the grid
 */
- (CGFloat)gridLength;
#ifndef GLYPHS_VIEWER
@property (nonatomic, assign) CGFloat keyboardIncrement;

@property (nonatomic, assign) CGFloat keyboardIncrementBig;

@property (nonatomic, assign) CGFloat keyboardIncrementHuge;

@property (nonatomic, assign) BOOL previewRemoveOverlap;

@property (nonatomic, assign) BOOL snapToObjects;

- (BOOL)importAFM:(NSString *)AFMString fontMaster:(nullable GSFontMaster *)fontMaster verticalMetrics:(BOOL)verticalMetrics metrics:(BOOL)doMetrics kerning:(BOOL)doKerning error:(out NSError **)error;
#ifndef GLYPHS_LITE
/** Recalculates the temp font.

 Call it, if you changed something like the glyph set or the features and need to make sure the temp font is up to date. This is usually done automatically.

 @param error if there is a problem, it returns an NSError object (by reference) that contains details.
 @return YES if successful, NO, if not.
 @see tempOTFFont
 */
- (BOOL)compileTempFontError:(out NSError **)error;

/** The path to the temp font

 This font contains no outlines and no kerning but the full GSUB table. It is used for the feature preview in edit view.
 */
@property (nonatomic, strong, nullable) NSString *tempOTFFont;

@property (nonatomic, strong, nullable) COFont *compositorFont;
@property (nonatomic, strong, nullable) NSDictionary *tempProduction2NiceNames;
#endif
#endif

@property (nonatomic, strong) NSArray *displayStrings;
@property (nonatomic, strong) NSString *appVersion;
@property (nonatomic, strong) NSString *storedFileType;
@property (nonatomic) GSFormatVersion formatVersion;
@property (nonatomic) GSFormatVersion storedFormatVersion;

#ifndef GLYPHS_VIEWER
/**
 Adds a new font info value to the array specified by `key` or updates an existing one.

 @param name 		The key whose plural form specifies an array property of `GSFontInfoValue` objects on the receiver.
 @param value 		The actual value to be added.
 @param languageTag	The language under which the the value should be stored. Defaults to `English` if nil is passed.
 */
- (void)setProperty:(NSString *)name value:(nullable id)value languageTag:(nullable NSString *)languageTag;

- (nullable GSFontInfoProperty *)propertyForName:(NSString *)name;

- (nullable GSFontInfoValue *)propertyForName:(NSString *)name languageTag:(NSString *)languageTag;

- (nullable NSString *)defaultPropertyForName:(nonnull NSString *)name;

+ (NSArray *)allowedPropertyKeys;

+ (NSArray *)legacyInfoKeys;

@property (nullable, nonatomic, strong) NSUndoManager *undoManager;

- (void)disableUndo;
- (void)enableUndo;

#endif

/**
 @note The receiver’s implementation of `undoManager` returns the parent’s undo manager. It is only used for font info and for adding/removing glyphs. Each glyph has its own undo manager (see `-[GSGlyph undoManager]`).
 */
@property (nullable, nonatomic, weak) GSDocument *parent;

- (void)invalidateCustomParameterCache;

#ifndef GLYPHS_VIEWER
/**
 Tags in all glyphs.
 */
@property (nullable, nonatomic, readonly) NSArray<NSString *> *allTags;

// for use from FEAKit only
- (BOOL)makeOTFCompatibleFeatureCode;

- (nonnull NSString *)nameUI;

- (GSFontInfoValueLocalized *)preferredFamilyNames:(out NSError **)error;
#endif
#pragma mark - Start auto interface

- (void)lockReadGlyphs;

- (void)unlockReadGlyphs;

- (void)lockWriteGlyphs;

- (void)unlockWriteGlyphs;

#pragma GSAutoCodeStart methods

/// The fontName.
@property (nonatomic, strong) NSString *fontName;

#pragma mark Axes

/// The axes.
@property (nonatomic, strong) NSMutableArray<GSAxis *> *axes;

/** The number of axes */
- (NSUInteger)countOfAxes;

/** Returns object at idx in axes

 @param idx The index
 @return the object at index
 */
- (GSAxis *)objectInAxesAtIndex:(NSUInteger)idx;

/** Returns the index of axis in axes

 @param axis the object
 @return the index of the object
 */
- (NSUInteger)indexOfObjectInAxes:(GSAxis *)axis;

/** Adds the axis

 @param axis the object to be added
 */
- (void)addAxis:(GSAxis *)axis;

/** Inserts the axis at index into axes

 @param axis The object to insert
 @param idx The index
 */
- (void)insertObject:(GSAxis *)axis inAxesAtIndex:(NSUInteger)idx;

/** Removes the axis

 @param axis the object to be removed
 */
- (void)removeObjectFromAxes:(GSAxis *)axis;

/** Removes the axis at idx

 @param idx The index
 */
- (void)removeObjectFromAxesAtIndex:(NSUInteger)idx;

#pragma mark Properties

/// The properties.
@property (nonatomic, strong) NSMutableArray<GSFontInfoProperty *> *properties;

/** The number of properties */
- (NSUInteger)countOfProperties;

/** Returns object at idx in properties

 @param idx The index
 @return the object at index
 */
- (GSFontInfoProperty *)objectInPropertiesAtIndex:(NSUInteger)idx;

/** Returns the index of property in properties

 @param property the object
 @return the index of the object
 */
- (NSUInteger)indexOfObjectInProperties:(GSFontInfoProperty *)property;

/** Adds the property

 @param property the object to be added
 */
- (void)addProperty:(GSFontInfoProperty *)property;

/** Inserts the property at index into properties

 @param property The object to insert
 @param idx The index
 */
- (void)insertObject:(GSFontInfoProperty *)property inPropertiesAtIndex:(NSUInteger)idx;

#ifndef GLYPHS_VIEWER
/** Removes the property

 @param property the object to be removed
 */
- (void)removeObjectFromProperties:(GSFontInfoProperty *)property;

/** Removes the property at idx

 @param idx The index
 */
- (void)removeObjectFromPropertiesAtIndex:(NSUInteger)idx;
#endif

#pragma mark Custom Parameter

/// @name customParameters

/**
 The customParameters.
 A list of customParameters objects
 */
@property (nonatomic, strong) NSMutableArray<GSCustomParameter *> *customParameters;

/** The count of customParameters */
- (NSUInteger)countOfCustomParameters;

- (GSCustomParameter *)objectInCustomParametersAtIndex:(NSUInteger)idx;

- (BOOL)customBoolValueForKey:(NSString *)key;

- (nullable id)customColorValueForKey:(NSString *)key;

/// The value of the customParameters where name == Key
- (nullable id)customValueForKey:(NSString *)key;

/// The customParameters where name == Key
- (nullable GSCustomParameter *)customParameterForKey:(NSString *)key;

- (GSCustomParameter *)customParameterActiveForKey:(NSString *)key;

#ifndef GLYPHS_VIEWER
/** Set the value for key

 It will look for an existing parameter with the name an overwrite its value, or adds a new parameter
 @param value The value to add
 @param key   The name of the parameter
 */
- (void)setCustomValue:(id)value forKey:(NSString *)key;

- (void)addCustomParameter:(GSCustomParameter *)property;

- (void)removeObjectFromCustomParameters:(GSCustomParameter *)customParameter;

/** Removes the first parameter with then Name

 @param key The name
 */
- (void)removeObjectFromCustomParametersForKey:(NSString *)key;

- (void)insertObject:(GSCustomParameter *)customParameter inCustomParametersAtIndex:(NSUInteger)idx;

- (void)removeObjectFromCustomParametersAtIndex:(NSUInteger)idx;

- (void)replaceObjectInCustomParametersAtIndex:(NSUInteger)idx withObject:(GSCustomParameter *)customParameter;
#endif

/// The note.
@property (nonatomic, strong) NSString *note;

#pragma mark User Data

/// @name UserData
/** Place to store data.

 Here it is possible to store something. Please use a unique key.
 The objects should be able to serialize to a plist. If they are not, they should return all infos to store in description (as String).
 */
@property (strong, nonatomic, nullable) NSDictionary *userData;

/**
 convenience accessor to get to the content of the userData dict

 @param key the key
 @return the data stored with key
 */
- (nullable NSObject *)userDataForKey:(NSString *)key;

/** Adds something to the fonts userData.

 This also triggers undo/document dirty state.

 @param value The object should be able to serialize to a plist. If they are not, they should return all infos to store in description (as String).
 @param key   Please use an unique key that gives some indication who put it there (e.g. prefix it with your name or project).
 */
- (void)setUserData:(nullable id)value forKey:(nonnull NSString *)key;

/** Removed the object with this key.

 @param key The key to remove
 */
- (void)removeUserDataForKey:(NSString *)key;
#pragma GSAutoCodeEnd methods
@end

NS_ASSUME_NONNULL_END
