//
//  GSGlyph.h
//  FontBezier Doc
//
//  Created by Georg Seifert on 20.10.05.
//  Copyright 2005 schriftgestaltung.de. All rights reserved.
//

#import <GlyphsCore/GSFont.h>
#import <GlyphsCore/GSLayer.h>
#import <GlyphsCore/GSSaveContext.h>
#import <GlyphsCore/GSUndoManager.h>
#import <GlyphsCore/GSUserDataProtocol.h>

@class GSFont;
@class MGOrderedDictionary;
@class GSInstance;
@class GSGlyphInfo;

#define OTFErrorGenerateFont 528
#define OTFErrorAddInflections 529
#define OTFErrorGlyphsWithError 530
NS_ASSUME_NONNULL_BEGIN

/// A named glyph and its layer collection in a font.
///
/// A glyph belongs to a ``GSFont`` and provides the information shared by all drawings of that glyph.
/// This includes character mappings, classification, export settings, metrics keys, kerning groups, and glyph-local axes.
/// A detached glyph is valid, but operations that depend on masters, other glyphs, or font lookup data require a font.
///
/// The *glyph name* identifies the glyph within Glyphs and is used by references such as components.
/// The *production name* identifies the glyph in exported font files when it differs from the glyph name.
///
/// Unicode values associate a glyph with characters but do not identify the glyph; a glyph can have multiple Unicode values or none.
///
/// A glyph owns a collection of ``GSLayer`` objects.
/// Drawing and editing take place on those layers.
/// Layer compatibility determines whether corresponding drawings can be interpolated.
///
/// Not every glyph is exported, and some glyphs are only used as internal components in other glyphs.
@interface GSGlyph : NSObject <NSCoding, NSCopying, GSUserDataProtocol, GSUndoClientProtocol> {
	MGOrderedDictionary *_layers;
	NSString *_name;
	NSMutableOrderedSet *_unicodes;
	NSString *_script;
	NSString *_note;
	NSString *_category;
	NSString *_subCategory;
	NSString *_group;
	int16_t _groupIdx;
	GSCase _case;
	GSWritingDirection _direction;
	NSString *_leftMetricsKey;
	NSString *_widthMetricsKey;
	NSString *_rightMetricsKey;
	NSString *_vertWidthMetricsKey;
	NSString *_vertOriginMetricsKey;
	NSString *_topMetricsKey;
	NSString *_bottomMetricsKey;

	BOOL _export;
	BOOL _editable;
	NSColor *_color;
	GSLabelColor _colorIndex;
	NSMutableDictionary *_userData;
	NSDate *_lastChange;
	NSInteger _changeCount;

	NSString *_production;
	BOOL _storeScript;
	BOOL _storeCategory;
	BOOL _storeSubCategory;
	BOOL _storeCase;
	BOOL _storeProduction;
	BOOL _storeDirection;
	NSString *_sortName;
	NSString *_sortNameKeep;
	BOOL _storeSortName;

	BOOL _locked;
	BOOL _justLocked;
	NSMutableOrderedSet<NSString *> *_tags;

#pragma GSAutoCodeStart ivars

#pragma GSAutoCodeEnd ivars
}

/// Creates a minimally configured glyph for bulk construction.
///
/// The caller must provide the glyph name and any other required state before using the glyph.
/// Use ``initWithName:`` for general glyph creation.
- (instancetype)initFast NS_REFINED_FOR_SWIFT;

/// Creates a glyph with a name and no layers.
///
/// The glyph is not added to a font.
///
/// - Parameter name: The glyph name.
- (instancetype)initWithName:(NSString *)name;

/// Whether another glyph has matching layer contents and core glyph settings.
///
/// Unicode values, tags, naming and classification overrides, metrics and kerning settings, color, user data, glyph axes, and layers are compared.
/// ``baseString``, ``id``, ``glyphId``, lock state, parent, change tracking, and undo history are not compared.
/// This method does not replace `NSObject` identity equality.
///
/// - Parameter other: The glyph to compare.
- (BOOL)isEqualToGlyph:(GSGlyph *)other;

#pragma mark - Properties

/// The font that contains the glyph, or `nil` for a detached glyph.
///
/// Use the glyph collection of ``GSFont`` to attach or detach a glyph.
/// Assigning this property alone does not update the font’s glyph collection or lookup data.
@property (weak, nonatomic, nullable) GSFont *parent;

/// The font that contains the glyph, or `nil` for a detached glyph.
///
/// This is a read-only alias for ``parent``.
@property (readonly, nonatomic, nullable) GSFont *font;
/// The pending glyph edit count used for glyph-specific autosaving and change indicators.
///
/// Edits, undo, and redo adjust this value.
@property (assign, nonatomic) NSInteger changeCount;

/// The glyph name used within Glyphs.
///
/// Glyph names identify glyphs in the font and may use the descriptive naming conventions recognized by Glyphs.
/// Exported font files may use a different ``production`` name.
/// Use ``validateName:`` before assigning a name supplied by an API client.
/// Assigning `nil` or an empty string does not change the name.
@property (nonatomic, copy, nullable) NSString *name;
/// The first Unicode code point associated with the glyph, as an uppercase hexadecimal string.
///
/// Assigning this property replaces all existing Unicode code points.
/// A value of `nil` leaves the glyph without an associated Unicode code point.
@property (nonatomic, copy, nullable) NSString *unicode;

/// The Unicode code points associated with the glyph, as an ordered set of uppercase hexadecimal strings.
///
/// Most glyphs have zero or one Unicode code point, but a glyph can have several.
/// The first value is the primary Unicode code point used by singular convenience properties such as ``unicode`` and ``unicodeChar``.
/// Glyph information can assign Unicode code points when the glyph name changes.
/// Use this property or the Unicode mutation methods instead of modifying the returned set directly.
@property (strong, nonatomic, nullable) NSOrderedSet *unicodes;

/// Assigns Unicode code points without updating related state.
///
/// This method does not register undo or update glyph lookup in the containing font.
/// The caller is responsible for supplying valid Unicode code point strings.
/// Use ``unicodes`` for general assignment.
///
/// - Parameter unicodes: The Unicode code points as hexadecimal strings.
- (void)setUnicodesFast:(nullable NSOrderedSet *)unicodes;

/// Adds a Unicode code point while preserving the existing code points.
///
/// - Parameter unicode: The Unicode code point as a hexadecimal string.
- (void)addUnicode:(NSString *)unicode;

/// Removes a Unicode code point while preserving the order of the remaining code points.
///
/// - Parameter unicode: The Unicode code point as a hexadecimal string.
- (void)removeUnicode:(NSString *)unicode;

/// The number of associated Unicode code points.
- (NSUInteger)countOfUnicodes;

/// The numeric value of the first associated Unicode code point, or `0` when there is none.
///
/// The value does not distinguish U+0000 from the absence of an associated code point.
@property (nonatomic, readonly) UTF32Char unicodeChar;

/// A free-form note associated with the glyph.
///
/// The note is stored in the Glyphs file and does not affect font export.
@property (nonatomic, copy, nullable) NSString *note;

/// The writing system associated with the glyph.
///
/// This value is usually supplied by the Glyph Info Database.
/// Set ``storeScript`` to `YES` to persist a glyph-local override.
@property (nonatomic, copy, nullable) GSScriptID script;
/// Whether ``script`` is stored as glyph-local glyph info.
///
/// Setting this to `NO` replaces ``script`` with the value supplied by the Glyph Info Database.
@property (nonatomic) BOOL storeScript NS_SWIFT_NAME(isStoringScript);

/// Whether the glyph uses CJK layout behavior.
///
/// This includes glyphs with a CJK script and glyphs using the full-width naming convention.
@property (nonatomic, readonly) BOOL isCJK;
/// Whether the glyph is rotated clockwise in vertical text.
///
/// This is derived from the naming conventions for rotated vertical forms and Mongolian glyphs.
@property (nonatomic, readonly) BOOL isVerticalRotationClockwise;

/// The broad classification used to interpret and organize the glyph.
///
/// Categories include letters, numbers, punctuation, marks, and symbols.
/// This value is usually supplied by the Glyph Info Database.
/// Set ``storeCategory`` to `YES` to persist a glyph-local override.
@property (nonatomic, copy, nullable) NSString *category;
/// Whether ``category`` is stored as glyph-local glyph info.
///
/// Setting this to `NO` replaces ``category`` with the value supplied by the Glyph Info Database.
@property (nonatomic) BOOL storeCategory NS_SWIFT_NAME(isStoringCategory);

/// The classification that refines ``category``.
///
/// This value is usually supplied by the Glyph Info Database.
/// Set ``storeSubCategory`` to `YES` to persist a glyph-local override.
@property (nonatomic, copy, nullable) NSString *subCategory;
/// Whether ``subCategory`` is stored as glyph-local glyph info.
///
/// Setting this to `NO` replaces ``subCategory`` with the value supplied by the Glyph Info Database.
@property (nonatomic) BOOL storeSubCategory NS_SWIFT_NAME(isStoringSubCategory);

/// The title of an explicit glyph group used for sorting and display.
///
/// This value is usually supplied by the Glyph Info Database together with ``groupIdx``.
/// Set ``storeGroup`` to `YES` to persist a glyph-local override of both values.
@property (nonatomic, copy, nullable) NSString *group;
/// The ordering value of an explicit glyph group.
///
/// Glyphs with the same positive value belong to the same group.
/// A value less than or equal to zero uses category-based grouping.
@property (nonatomic) int16_t groupIdx;
/// Whether ``group`` and ``groupIdx`` are stored as glyph-local glyph info.
@property (nonatomic) BOOL storeGroup NS_SWIFT_NAME(isStoringGroup);

/// The case classification used to interpret and organize the glyph.
///
/// This value is usually supplied by the Glyph Info Database.
/// Set ``storeCase`` to `YES` to persist a glyph-local override.
- (GSCase)case NS_REFINED_FOR_SWIFT;
/// Assigns the case classification used to interpret and organize the glyph.
- (void)setCase:(GSCase)aCase NS_REFINED_FOR_SWIFT;
/// Assigns a case classification without recording a glyph change.
///
/// Use ``setCase:`` for general assignment.
- (void)setCaseFast:(GSCase)aCase;
/// Whether the case classification is stored as glyph-local glyph info.
///
/// Setting this to `NO` replaces the case classification with the value supplied by the Glyph Info Database.
@property (nonatomic) BOOL storeCase NS_SWIFT_NAME(isStoringCase);

/// Whether the production name is stored as a custom value.
///
/// Setting this to `NO` replaces ``production`` with the production name derived from the glyph information.
@property (nonatomic) BOOL storeProduction NS_SWIFT_NAME(isStoringProduction);
/// The preferred glyph name for exported font files.
///
/// When this is `nil`, export derives a production name from the glyph name, Unicode values, and glyph information.
/// Set ``storeProduction`` to `YES` to retain a custom production name.
@property (strong, nonatomic, nullable) NSString *production;

/// Whether ``direction`` is stored as glyph-local glyph info.
///
/// Setting this to `NO` replaces ``direction`` with the value supplied by the Glyph Info Database.
@property (nonatomic) BOOL storeDirection NS_SWIFT_NAME(isStoringDirection);
/// The writing direction associated with the glyph.
///
/// This value is usually supplied by the Glyph Info Database.
/// Set ``storeDirection`` to `YES` to persist a glyph-local override.
@property (nonatomic) GSWritingDirection direction;

/// The Unicode string represented by the glyph’s character composition.
///
/// This is usually derived from glyph information and can contain multiple Unicode code points.
/// It is distinct from ``unicodes``, which contains alternate code points associated with the glyph.
@property (nonatomic, strong, nullable) NSString *baseString;

#ifndef GLYPHS_VIEWER
/// A property-list representation in a Glyphs source format.
///
/// Property-list encoding supports format 3 and later.
///
/// - Parameter format: The source format used for the representation.
/// - Parameter error: On return, an error that prevented encoding.
- (nullable NSDictionary<NSString *, id> *)propertyListValueFormat:(GSFormatVersion)format error:(out NSError **)error;

/// A property-list representation using specified save options.
///
/// Property-list encoding supports format 3 and later.
/// Only ``GSSaveOptionWriteLastChange`` affects the glyph representation.
///
/// - Parameter format: The source format used for the representation.
/// - Parameter options: Options controlling the represented data.
/// - Parameter error: On return, an error that prevented encoding.
- (nullable NSDictionary<NSString *, id> *)propertyListValueFormat:(GSFormatVersion)format options:(GSSaveOptions)options error:(out NSError **)error;
#endif

/// Glyph-level metrics key for the left side bearing.
///
/// A layer-specific metrics key overrides this value.
@property (copy, nonatomic, nullable) NSString *leftMetricsKey;
/// Glyph-level metrics key for the advance width.
///
/// A layer-specific metrics key overrides this value.
@property (copy, nonatomic, nullable) NSString *widthMetricsKey;
/// Glyph-level metrics key for the right side bearing.
///
/// A layer-specific metrics key overrides this value.
@property (copy, nonatomic, nullable) NSString *rightMetricsKey;
/// Glyph-level metrics key for the top side bearing.
///
/// A layer-specific metrics key overrides this value.
@property (copy, nonatomic, nullable) NSString *topMetricsKey;
/// Glyph-level metrics key for the vertical origin.
///
/// A layer-specific metrics key overrides this value.
@property (copy, nonatomic, nullable) NSString *vertOriginMetricsKey;
/// Glyph-level metrics key for the vertical advance width.
///
/// A layer-specific metrics key overrides this value.
@property (copy, nonatomic, nullable) NSString *vertWidthMetricsKey;
/// Glyph-level metrics key for the bottom side bearing.
///
/// A layer-specific metrics key overrides this value.
@property (copy, nonatomic, nullable) NSString *bottomMetricsKey;

/// Kerning group on the side facing the preceding glyph for a writing direction.
///
/// - Parameter direction: The writing direction used to determine the preceding side.
- (nullable NSString *)previousKerningGroupForDirection:(GSWritingDirection)direction;

/// Sets the kerning group on the side facing the preceding glyph for a writing direction.
///
/// - Parameter group: The group name.
/// - Parameter direction: The writing direction used to determine the preceding side.
- (void)setPreviousKerningGroup:(NSString *)group forDirection:(GSWritingDirection)direction;

/// Prefixed kerning key on the side facing the preceding glyph for a writing direction.
///
/// - Parameter direction: The writing direction used to determine the preceding side.
- (nullable NSString *)previousKerningGroupIDforDirection:(GSWritingDirection)direction;

/// Sets the prefixed kerning key on the side facing the preceding glyph for a writing direction.
///
/// - Parameter groupId: The prefixed kerning key.
/// - Parameter direction: The writing direction used to determine the preceding side.
- (void)setPreviousKerningGroupID:(NSString *)groupId forDirection:(GSWritingDirection)direction;

/// Kerning group on the side facing the following glyph for a writing direction.
///
/// - Parameter direction: The writing direction used to determine the following side.
- (nullable NSString *)nextKerningGroupForDirection:(GSWritingDirection)direction;

/// Sets the kerning group on the side facing the following glyph for a writing direction.
///
/// - Parameter group: The group name.
/// - Parameter direction: The writing direction used to determine the following side.
- (void)setNextKerningGroup:(NSString *)group forDirection:(GSWritingDirection)direction;

/// Prefixed kerning key on the side facing the following glyph for a writing direction.
///
/// - Parameter direction: The writing direction used to determine the following side.
- (nullable NSString *)nextKerningGroupIDforDirection:(GSWritingDirection)direction;

/// Sets the prefixed kerning key on the side facing the following glyph for a writing direction.
///
/// - Parameter groupId: The prefixed kerning key.
/// - Parameter direction: The writing direction used to determine the following side.
- (void)setNextKerningGroupID:(NSString *)groupId forDirection:(GSWritingDirection)direction;

/// Kerning group for pairs on the left side.
@property (copy, nonatomic, nullable) NSString *leftKerningGroup;

/// Kerning group for pairs on the right side.
@property (copy, nonatomic, nullable) NSString *rightKerningGroup;

/// Prefixed kerning key corresponding to ``leftKerningGroup``.
///
/// Left-side groups use the `@MMK_R_` prefix because they occur as the right member of a horizontal kerning pair.
@property (copy, nonatomic, nullable) NSString *leftKerningGroupId;

/// Prefixed kerning key corresponding to ``rightKerningGroup``.
///
/// Right-side groups use the `@MMK_L_` prefix because they occur as the left member of a horizontal kerning pair.
@property (copy, nonatomic, nullable) NSString *rightKerningGroupId;

/// Kerning group for pairs on the top side.
@property (copy, nonatomic, nullable) NSString *topKerningGroup;

/// Kerning group for pairs on the bottom side.
@property (copy, nonatomic, nullable) NSString *bottomKerningGroup;

/// Prefixed kerning key corresponding to ``topKerningGroup``.
///
/// Top-side groups use the `@MMK_B_` prefix because they occur as the second member of a vertical kerning pair.
@property (copy, nonatomic, nullable) NSString *topKerningGroupId;

/// Prefixed kerning key corresponding to ``bottomKerningGroup``.
///
/// Bottom-side groups use the `@MMK_T_` prefix because they occur as the first member of a vertical kerning pair.
@property (copy, nonatomic, nullable) NSString *bottomKerningGroupId;

#ifndef GLYPHS_VIEWER
/// Validates the syntax of a proposed kerning group name.
///
/// This does not check whether the group is used by other glyphs or has kerning values.
///
/// - Parameter ioValue: The proposed group name, or `nil`.
/// - Parameter outError: On return, an error describing invalid syntax.
/// - Returns: Whether the proposed value uses valid kerning group syntax.
- (BOOL)validateKerningGroup:(id __nullable *__nullable)ioValue error:(NSError **)outError;

/// Validates the syntax of a proposed metrics key.
///
/// This does not resolve references or calculate a metric value.
///
/// - Parameter ioValue: The proposed metrics key, or `nil`.
/// - Parameter outError: On return, an error describing invalid syntax.
/// - Returns: Whether the proposed value uses valid metrics key syntax.
- (BOOL)validateMetricsKey:(id __nullable *__nullable)ioValue error:(NSError **)outError;
#endif

#ifndef __cplusplus // RMX complains about that.

/// Whether the glyph is marked for inclusion in exported font files.
@property (nonatomic, getter=isExporting) BOOL export;
#endif

/// The color label used to organize the glyph, or `nil` if no color label is assigned.
///
/// For a standard color label, this resolves ``colorIndex`` using the current label color palette.
/// Setting a color stores a custom color label and clears ``colorIndex``.
@property (retain, nonatomic, nullable) NSColor *color;

/// A standard color label, or ``GSLabelColor/noColor`` if the glyph has a custom color label or no color label.
///
/// Setting a standard color label clears a custom ``color``.
@property (assign, nonatomic) GSLabelColor colorIndex;

#ifndef GLYPHS_VIEWER
/// The undo manager associated with edits to the glyph.
///
/// Each glyph normally maintains an independent undo history.
/// Assigning `nil` disables undo registration for operations that use this manager.
@property (strong, nonatomic, nullable) GSUndoManager *undoManager;

/// The glyph’s undo manager when undo registration is enabled, or `nil` otherwise.
@property (nonatomic, readonly, nullable) GSUndoManager *undoManagerCheck;

#endif
/// The current index in the containing font’s glyph collection.
///
/// The font maintains this value as its glyphs are sorted or reordered.
/// A detached glyph does not have a meaningful glyph index.
/// Do not use this value as persistent identity; use ``id`` instead.
@property (nonatomic) NSUInteger glyphId;

/// The identifier used to refer to the glyph independently of its name.
///
/// The identifier is unique among the glyphs in a font and is used by kerning and identifier-based lookup.
/// It exists only at runtime and is regenerated when the glyph is loaded.
/// Do not use it to refer to a glyph across font sessions.
/// Renaming the glyph does not change this identifier.
/// Adding a glyph to a font replaces a missing or duplicate identifier.
/// Do not change the identifier while the glyph belongs to a font because existing references are not updated.
@property (strong, nonatomic) NSString *id;
/// The key used instead of ``name`` for predefined glyph sorting.
///
/// This value is usually supplied by the Glyph Info Database.
/// Set ``storeSortName`` to `YES` to persist a glyph-local override.
@property (strong, nonatomic, nullable) NSString *sortName;
/// The sorting key used when alternate glyphs are kept together.
///
/// This is usually derived together with ``sortName`` by the Glyph Info Database.
///
/// - SeeAlso: ``GSFont/keepAlternatesTogether``.
@property (strong, nonatomic, nullable) NSString *sortNameKeep NS_SWIFT_NAME(sortNameForKeepAlternatesTogether);
/// Whether ``sortName`` and ``sortNameKeep`` are stored as glyph-local glyph info.
///
/// Setting this to `NO` restores sorting information from the Glyph Info Database.
@property (nonatomic) BOOL storeSortName NS_SWIFT_NAME(isStoringSortName);

/// Whether the glyph uses a tabular-figure naming convention.
///
/// This recognizes the `.tf`, `.tosf`, and `.tnum` name components and does not compare advance widths.
@property (nonatomic, readonly) BOOL isTabular;

/// Changes whether editing the glyph is disabled without registering undo.
///
/// Use this when restoring or constructing a glyph rather than for an interactive edit.
///
/// - Parameter locked: Whether editing is disabled.
- (void)setLockedFast:(BOOL)locked;

/// Prepares the glyph for synchronized access.
///
/// Glyphs added to a font are prepared automatically.
/// Call this before sharing a detached glyph between threads.
- (void)initLock;

/// Whether the glyph has been prepared for synchronized access.
- (BOOL)hasLock;

/// Acquires shared access to glyph-level cached state.
///
/// Balance this call with ``unlockRead`` on the same thread.
/// Read and write access may be nested on the same thread.
- (void)lockRead;
/// Releases shared access acquired with ``lockRead``.
- (void)unlockRead;
/// Acquires exclusive access to glyph-level cached state.
///
/// Balance this call with ``unlockWrite`` on the same thread.
/// Upgrading from read access is not atomic, so values observed before the upgrade may change.
- (void)lockWrite;
/// Releases exclusive access acquired with ``lockWrite``.
- (void)unlockWrite;

/// Acquires shared access to the layer collection.
///
/// This does not by itself protect mutable contents of individual layers.
/// Balance this call with ``unlockReadLayers`` on the same thread.
/// Read and write access may be nested on the same thread.
- (void)lockReadLayers;
/// Releases shared access acquired with ``lockReadLayers``.
- (void)unlockReadLayers;
/// Acquires exclusive access to the layer collection.
///
/// This does not by itself protect mutable contents of individual layers.
/// Balance this call with ``unlockWriteLayers`` on the same thread.
/// Upgrading from read access is not atomic, so values observed before the upgrade may change.
- (void)lockWriteLayers;
/// Releases exclusive access acquired with ``lockWriteLayers``.
- (void)unlockWriteLayers;

/// The date of the most recent operation used to invalidate glyph-dependent caches.
///
/// This value may be `nil` before an operation has been recorded.
@property (nonatomic, strong, nullable) NSDate *lastOperation;

/// The glyph-local axes used by Smart Components.
///
/// Glyph-local axes describe variation within this glyph and follow the font axes in a complete design-space location.
/// Each axis in this collection belongs to the glyph.
/// Use this property or the axis mutation methods instead of modifying the returned array directly.
@property (strong, nonatomic) NSArray<GSAxis *> *axes;

/// The number of glyph-local axes.
@property (nonatomic, readonly) NSUInteger countOfAxes;

/// The axes defining a complete design-space location for the glyph.
///
/// Font axes appear first, followed by glyph-local axes.
/// The glyph must belong to a font.
@property (strong, nonatomic, readonly) NSArray<GSAxis *> *allAxes;

/// The total number of font axes and glyph-local axes.
- (NSUInteger)countOfAllAxes;

#ifndef GLYPHS_LITE
/// The glyph-local axis at an index, or `nil` when the index is out of range.
///
/// - Parameter idx: The index in ``axes``.
- (nullable GSAxis *)objectInAxesAtIndex:(NSUInteger)idx NS_SWIFT_NAME(axis(atIndex:));
#ifndef QUICKLOOK
/// Inserts a glyph-local axis at an index.
///
/// The axis becomes owned by the glyph.
///
/// - Parameter axis: The axis to insert.
/// - Parameter idx: An index from zero through ``countOfAxes``.
- (void)insertObject:(GSAxis *)axis inAxesAtIndex:(NSUInteger)idx NS_SWIFT_NAME(insertAxis(_:atIndex:));

/// Removes the glyph-local axis at an index.
///
/// The removed axis no longer belongs to the glyph.
///
/// - Parameter idx: A valid index in ``axes``.
- (void)removeObjectFromAxesAtIndex:(NSUInteger)idx NS_SWIFT_NAME(removeAxis(atIndex:));

/// Replaces the glyph-local axis at an index.
///
/// The replacement axis becomes owned by the glyph, and the replaced axis no longer belongs to the glyph.
///
/// - Parameter idx: A valid index in ``axes``.
/// - Parameter axis: The replacement axis.
- (void)replaceObjectInAxesAtIndex:(NSUInteger)idx withObject:(GSAxis *)axis NS_SWIFT_NAME(replaceAxis(atIndex:with:));

/// Computes the internal coordinate range of each selected axis.
///
/// The output buffers use the order of `axes` and must each provide space for `axes.count` values.
/// Master layers and Intermediate layers contribute coordinate values.
/// The default value of a glyph-local axis also contributes to its range.
/// When `masterId` is provided, a glyph-local axis uses only layer values associated with that master.
/// This does not restrict font-axis values or the default value of a glyph-local axis.
/// A minimum greater than its corresponding maximum indicates that no qualifying value was found.
///
/// - Parameter internMin: The buffer that receives the minimum internal coordinates.
/// - Parameter internMax: The buffer that receives the maximum internal coordinates.
/// - Parameter axes: The axes whose ranges to compute.
/// - Parameter masterId: The associated master identifier used to restrict glyph-local-axis layer values, or `nil` to include layers associated with every master.
- (void)axesRanges:(CGFloat *)internMin internMax:(CGFloat *)internMax axes:(NSArray<GSAxis *> *)axes masterId:(nullable NSString *)masterId NS_REFINED_FOR_SWIFT;

#endif
#endif

/// The character for the first associated Unicode code point, or an empty string when this convenience API cannot represent it.
- (NSString *)charString;

/// Creates a glyph from a Glyphs file dictionary representation.
///
/// - Parameter glyphDict: The dictionary representation of the glyph.
/// - Parameter formatVersion: The Glyphs file format version used to interpret the representation.
- (instancetype)initWithDict:(NSDictionary *)glyphDict format:(GSFormatVersion)formatVersion;

#ifndef GLYPHS_VIEWER

/// Writes the glyph in Glyphs source syntax to an open file.
///
/// The save context controls optional data such as layers and the last-change timestamp.
///
/// - Parameter file: An open writable file positioned where the glyph content is written.
/// - Parameter formatVersion: The source format used for the representation.
/// - Parameter context: The options and shared state for the save operation.
/// - Parameter error: On return, an error that prevented encoding.
/// - Returns: Whether the glyph was encoded successfully.
- (BOOL)saveToFile:(FILE *)file format:(GSFormatVersion)formatVersion context:(GSSaveContext *)context error:(NSError **)error;

#endif
#pragma mark - Methods

#ifndef GLYPHS_VIEWER
#ifndef LIBCORE
/// Checks whether a glyph name can be assigned to the receiver.
///
/// In addition to the name syntax, this checks the glyph information and prevents duplicate names within the font.
///
/// - Parameter name: The proposed glyph name.
/// - Returns: An error describing why the name is invalid, or `nil` when the name is valid.
- (nullable NSError *)validateName:(NSString *)name;

/// Finds the standard glyph name corresponding to a nonstandard name.
///
/// - Parameter name: A name containing characters that are not valid in glyph names.
/// - Returns: The corresponding standard name, or `nil` when no replacement is known.
- (nullable NSString *)ensureValidName:(NSString *)name;

/// Checks whether a string follows the glyph name syntax.
///
/// This does not check for duplicate names within a font.
///
/// - Parameter name: The proposed glyph name.
/// - Parameter allowSpaces: Whether spaces are permitted within the name.
/// - Parameter error: On failure, an error describing the invalid name.
+ (BOOL)isValidNameString:(NSString *)name allowSpaces:(BOOL)allowSpaces error:(NSError **)error;

/// Checks whether a string uses the uppercase hexadecimal syntax for a Unicode code point.
///
/// This does not check whether the code point is already assigned to another glyph in the font.
///
/// - Parameter unicode: The proposed Unicode code point string.
/// - Parameter error: On failure, an error describing the invalid string.
+ (BOOL)isValidUnicodeString:(NSString *)unicode error:(NSError **)error;
#endif
#endif

/// Assigns a glyph name without updating related state.
///
/// This method does not update glyph information, name lookup in the containing font, undo, observation, or change notifications.
/// Use ``name`` for general renaming.
///
/// - Parameter name: The glyph name.
- (void)setNameFast:(NSString *)name;

/// Assigns a glyph name and updates name lookup in the containing font.
///
/// The new name is available through name lookup in the containing font.
/// This method does not update glyph information, undo, observation, or change notifications.
/// Use ``name`` for general renaming.
///
/// - Parameter name: The glyph name.
- (void)setNameFastCache:(NSString *)name;

/// Assigns a glyph name and updates related glyph information.
///
/// - Parameter name: The glyph name.
/// - Parameter changeName: Whether glyph information may replace the supplied name with its standard glyph name.
- (void)setName:(NSString *)name changeName:(BOOL)changeName;

/// Assigns a glyph name with control over related updates.
///
/// This is a low-level renaming method.
/// Use ``name`` for general renaming.
///
/// - Parameter name: The glyph name.
/// - Parameter changeName: Whether glyph information may replace the supplied name with its standard glyph name.
/// - Parameter update: Whether to update Unicode values and other glyph information for the name.
/// - Parameter validate: Whether a nonstandard name may be replaced with its standard glyph name even when `changeName` is `NO`.
- (void)setName:(NSString *)name changeName:(BOOL)changeName update:(BOOL)update validate:(BOOL)validate;

#pragma mark - Layers

/// The layers keyed by their layer identifiers.
///
/// A glyph in a font normally has one master layer for each font master and can contain additional Intermediate, Alternative, color, and backup layers.
/// A master layer uses its font master identifier as both its ``GSLayer/layerId`` and ``GSLayer/associatedMasterId``.
/// Other layers use a distinct ``GSLayer/layerId`` and identify the font master that supplies master-specific values through ``GSLayer/associatedMasterId``.
///
/// Layer indexes use the collection’s insertion order.
/// Use ``sortedLayers`` for font master order and ``setLayer:forId:`` or ``removeLayerForId:`` for individual changes.
/// Do not modify the returned dictionary directly because this bypasses layer ownership, undo, and notifications.
/// When assigning the complete collection, each key must match the corresponding ``GSLayer/layerId``.
@property (strong, nonatomic) NSDictionary<NSString *, GSLayer *> *layers;

/// The number of layers.
- (NSUInteger)countOfLayers;

/// The layer for an identifier.
///
/// When a font master has this identifier but its master layer is missing, this method obtains the corresponding master layer and adds it to the glyph when necessary.
/// Use ``layerForIdFast:`` for a lookup that does not add a layer.
///
/// - Parameter key: A layer or font master identifier.
- (nullable GSLayer *)layerForId:(nonnull NSString *)key;

/// The existing layer for an identifier, or `nil` when the glyph does not contain it.
///
/// This method does not create a missing master layer.
///
/// - Parameter key: A layer identifier.
- (nullable GSLayer *)layerForIdFast:(nonnull NSString *)key;

/// The first layer with an exact matching name, or `nil` when no layer matches.
///
/// - Parameter name: The layer name.
- (nullable GSLayer *)layerForName:(nonnull NSString *)name;

#ifndef GLYPHS_LITE
/// The first layer with an exact matching name and associated font master, or `nil` when no layer matches.
///
/// - Parameter name: The layer name.
/// - Parameter masterID: The associated font master identifier.
- (nullable GSLayer *)layerForName:(nonnull NSString *)name masterId:(nonnull NSString *)masterID;

/// One layer for each font master identifier, in the requested order.
///
/// When `name` is non-`nil`, each layer must have that name and be associated with the corresponding font master.
/// When `name` is `nil`, this method obtains the master layer for each identifier.
/// Returns `nil` when any requested layer is unavailable.
///
/// - Parameter name: The required layer name, or `nil` for master layers.
/// - Parameter masterIDs: The font master identifiers that determine the layers and their order.
- (nullable NSArray<GSLayer *> *)layersForName:(nullable NSString *)name masterIDs:(NSArray<NSString *> *)masterIDs;

/// The first layer with a matching derived layer key, or `nil` when no layer matches.
///
/// - Parameter key: The value of ``GSLayer/layerKey`` to match.
/// - Parameter masterID: The required associated font master identifier, or `nil` to match any font master.
- (nullable GSLayer *)layerForKey:(NSString *)key masterId:(nullable NSString *)masterID;
#endif

#ifndef GLYPHS_VIEWER
/// The layer nearest to a design-space position within an exclusive distance tolerance, or `nil` when no layer qualifies.
///
/// - Parameter position: A buffer containing one internal coordinate for each font axis, in font axis order.
/// - Parameter associatedMasterId: The required associated font master identifier, or `nil` to consider all layers.
/// - Parameter onlyBraceLayer: Whether to consider only Intermediate layers.
/// - Parameter tolerance: The exclusive maximum Euclidean distance from `position`.
- (nullable GSLayer *)layerNearestToPosition:(CGFloat *)position associatedMasterId:(nullable NSString *)associatedMasterId onlyBraceLayer:(BOOL)onlyBraceLayer tolerance:(CGFloat)tolerance;
#endif

/// The layer at an index in insertion order.
///
/// - Parameter idx: A valid layer index.
- (GSLayer *)objectInLayersAtIndex:(NSUInteger)idx NS_SWIFT_NAME(layer(atIndex:));

/// Adds or replaces a layer under an identifier.
///
/// The layer becomes a child of the glyph and uses the identifier as its ``GSLayer/layerId``.
/// A font master identifier also becomes the layer’s ``GSLayer/associatedMasterId``, making it a master layer.
/// A non-master layer must already identify its associated font master.
///
/// - Parameter layer: The layer to add.
/// - Parameter key: The layer identifier, or the font master identifier for a master layer.
- (void)setLayer:(GSLayer *)layer forId:(NSString *)key;

/// The layers ordered by font master, with each master layer before the other layers associated with that font master.
- (NSArray<GSLayer *> *)sortedLayers;

/// Removes the layer for an identifier.
///
/// This method has no effect when the glyph does not contain the identifier.
///
/// - Parameter key: The layer identifier.
- (void)removeLayerForId:(NSString *)key;

#ifndef GLYPHS_LITE

/// Marks layer compatibility for reevaluation.
- (void)resetMasterCompatibilityCheckStatus;

/// Whether every layer group has matching structure for interpolation.
///
/// Compatibility includes shapes, anchor names, and path-component hints.
/// The participating groups follow the font’s compatibility and empty-layer settings.
- (BOOL)mastersCompatible;

/// Whether the specified layers have matching shapes, anchor names, and path-component hints.
///
/// The first layer establishes the required structure.
/// Inactive subsequent layers do not affect the result.
///
/// - Parameter fontMasterIds: The layer identifiers to compare.
- (BOOL)mastersCompatibleForLayerIds:(NSArray<NSString *> *)fontMasterIds;

/// Whether selected aspects of the specified layers have matching structure.
///
/// The first layer establishes the required structure.
/// Inactive subsequent layers do not affect the result.
///
/// - Parameter fontMasterIds: The layer identifiers to compare.
/// - Parameter options: The aspects of the layers to compare.
- (BOOL)mastersCompatibleForLayerIds:(NSArray<NSString *> *)fontMasterIds options:(GSLayerCompareFlags)options;

/// Whether the layers have matching shapes, anchor names, and path-component hints.
///
/// - Parameter layers: The layers to compare.
- (BOOL)mastersCompatibleForLayers:(NSArray<GSLayer *> *)layers;

/// Clears the shapes of active layers whose selected aspects do not match the first layer.
///
/// - Parameter fontMasterIds: The layer identifiers to inspect.
/// - Parameter options: The aspects of the layers to compare.
/// - Returns: The identifiers whose layers were retained.
- (NSArray<NSString *> *)removeIncompatibleLayerContent:(NSArray<NSString *> *)fontMasterIds options:(GSLayerCompareFlags)options;

/// Orders layers by font master, placing each master layer before the other layers associated with that font master.
///
/// - Parameter layers: The mutable layer array to reorder.
- (void)sortLayers:(NSMutableArray<GSLayer *> *)layers;

/// The layer identifier groups used to check compatibility and coordinate edits across corresponding layers.
///
/// A layer group is an ordered set of layer identifiers for layers that participate in the same interpolation or substitution context.
/// Intermediate, Alternative, and color layers can form groups distinct from the master layers.
/// The grouping follows the font’s compatibility and empty-layer settings.
- (NSArray<NSOrderedSet<NSString *> *> *)layerGroups;

/// The layer identifier groups required by a set of instances.
///
/// Passing `nil` for `instances` groups all active master, Intermediate, Alternative, and color layers independently of the font’s instances.
/// Groups that share a layer identifier are combined.
///
/// - Parameter instances: The instances that determine which layers participate, or `nil` for forced grouping.
/// - Parameter masters: The font masters to consider and include when necessary.
/// - Parameter ignoreEmptyLayers: Whether to omit layers without content.
/// - Parameter error: On return, an error encountered while resolving the masters of a variable instance.
- (NSArray<NSMutableOrderedSet<NSString *> *> *)layerGroupsInstances:(nullable NSArray<GSInstance *> *)instances masters:(nullable NSArray<GSFontMaster *> *)masters ignoreEmptyLayers:(BOOL)ignoreEmptyLayers error:(out NSError **)error;

/// The layer identifier groups formed without reference to configured instances.
///
/// Inactive layers are omitted.
///
/// - Parameter seenLayers: A set to which the identifiers included in a group are added, or `nil` when this information is not needed.
/// - Parameter ignoreEmptyLayers: Whether to omit layers without shapes or a background image.
- (NSMutableArray<NSMutableOrderedSet<NSString *> *> *)forcedLayerGroupIdsSeenLayers:(nullable NSMutableSet<NSString *> *)seenLayers ignoreEmptyLayers:(BOOL)ignoreEmptyLayers;

/// The forced layer group containing a layer, or `nil` when the layer is not in a group.
///
/// Empty layers participate in the grouping.
///
/// - Parameter layer: A layer belonging to the glyph.
- (nullable NSOrderedSet<NSString *> *)layerGroupIDSetForLayer:(GSLayer *)layer;

/// The forced layer group containing a layer, or `nil` when the layer is not in a group.
///
/// - Parameter layer: A layer belonging to the glyph.
/// - Parameter ignoreEmptyLayers: Whether to omit layers without shapes or a background image.
- (nullable NSOrderedSet<NSString *> *)layerGroupIDSetForLayer:(GSLayer *)layer ignoreEmptyLayers:(BOOL)ignoreEmptyLayers;

/// The forced layer group containing a layer as an array, or `nil` when the layer is not in a group.
///
/// Empty layers participate in the grouping.
///
/// - Parameter layer: A layer belonging to the glyph.
- (nullable NSArray<NSString *> *)layerGroupIDsForLayer:(GSLayer *)layer;

/// The identifiers of layers in the same group that have compatible shapes, anchors, and path-component hints.
///
/// Layers without shapes or a background image do not participate in the grouping.
/// Returns `nil` for a background layer or a layer that is not in a group.
///
/// - Parameter layer: A layer belonging to the glyph.
- (nullable NSArray<NSString *> *)compatibleLayerGroupIdsForLayer:(GSLayer *)layer;

/// The font masters including representations of active Intermediate-layer locations.
///
/// This allows instance interpolation to account for Intermediate-layer locations.
/// Returns `nil` when no qualifying Intermediate layer is found.
///
/// - Parameter masters: The original font masters.
/// - Parameter allKeys: The layer and font master identifiers to inspect.
- (nullable NSArray<GSFontMaster *> *)collectBraceLayerIDsMasters:(NSArray<GSFontMaster *> *)masters allKeys:(NSOrderedSet<NSString *> *)allKeys;

/// Marks the derived layer keys of all layers for reevaluation.
- (void)resetLayerKeys;

/// Ensures that an interpolated layer has hints from a structurally compatible source layer.
///
/// A configured hinting master is preferred over the other participating layers and font masters.
/// Existing PostScript or TrueType hints are retained.
///
/// - Parameter layer: The interpolated layer that receives hints when needed.
/// - Parameter layers: The layers participating in the interpolation.
/// - Parameter masters: The font masters participating in the interpolation.
/// - Parameter font: The font that supplies the hinting-master settings.
- (void)ensureHintsInLayer:(GSLayer *)layer layers:(NSArray<GSLayer *> *)layers masters:(NSArray<GSFontMaster *> *)masters font:(GSFont *)font;

/// Adds hint categories missing from a compatible target layer.
///
/// PostScript, TrueType, and path-component hints are considered independently.
/// The layers must have matching node and shape structure.
///
/// - Parameter source: The layer from which hints are copied.
/// - Parameter target: The layer that receives copies of missing hint categories.
- (void)transferHintsFromLayer:(GSLayer *)source to:(GSLayer *)target;
#endif
/// Invalidates shape-derived caches for every stored layer.
///
/// Use this after modifying outlines without using layer change notifications.
/// This method does not register undo or update ``changeCount``.
- (void)outlineHasChanges;

/// Creates a detached copy with selected layer and editing content.
///
/// Most glyph-level metadata is copied regardless of the options.
/// The options select the layer kinds and optional data to include.
/// A custom color requires ``GSGlyphCopyExtras``, and glyph-local axes require ``GSGlyphCopySpecialLayers``.
/// The returned glyph has no parent.
///
/// - Parameter options: The content and initialization behavior to use for the copy.
- (id)copyWithOptions:(GSGlyphCopyOptions)options;

/// Whether any layer uses a color-layer format.
///
/// This includes full-color, palette, SVG, and Apple bitmap color layers.
/// Color-layer formats are not mutually exclusive.
- (BOOL)isAnyColorGlyph;

/// Whether any layer is a full-color layer.
///
/// Full-color layers draw their shapes using shape paint and compositing attributes.
- (BOOL)isFullColorGlyph;

/// Whether any layer is a palette color layer.
///
/// Palette color layers contribute to OpenType COLR glyphs and select colors from CPAL palettes.
- (BOOL)isColorPaletteGlyph;

/// Whether any layer is an SVG color layer.
- (BOOL)isSVGColorGlyph;

/// Whether any layer is an Apple bitmap color layer.
///
/// Apple bitmap color layers contribute images to an OpenType `sbix` table.
- (BOOL)isAppleColorGlyph;

/// Whether the first shape of the first font master layer is a component whose glyph uses a color-layer format.
- (BOOL)hasColorsInComponents;

/// Whether any stored layer directly contains a component.
- (BOOL)hasComponents;

/// Whether a glyph name uses a recognized corner-glyph prefix.
///
/// The recognized prefixes are `_corner.`, `_cap.`, `_brush.`, `_segment.`, and `_head.`.
///
/// - Parameter name: The glyph name to classify.
+ (BOOL)isCornerName:(NSString *)name;

/// Whether the glyph name identifies a corner glyph.
///
/// Corner glyphs provide reusable outlines for corners, caps, brushes, segments, and heads.
- (BOOL)isCornerGlyph;

#ifndef GLYPHS_LITE
/// Whether the glyph uses Smart Component behavior.
///
/// Glyphs with glyph-local axes qualify, as do glyphs recognized by their classification, script, or naming convention.
- (BOOL)isSmartGlyph;
#endif

/// Whether icon-specific metrics and drawing behavior apply to the glyph.
///
/// Glyphs in an icon font qualify unless their category is SF Symbol.
/// Glyphs in other fonts qualify when their category is Icon.
- (BOOL)isIcon;

#ifndef GLYPHS_LITE
/// Whether the glyph category is SF Symbol.
- (BOOL)isSFSymbol;

/// Whether any glyph info is stored as a glyph-local override.
///
/// This includes category, subcategory, production name, script, direction, sorting, group, and case information.
- (BOOL)hasCustomGlyphInfo;

/// Whether any stored layer has special layer attributes.
///
/// Intermediate layers, Alternative layers, and other attributed layers satisfy this condition, regardless of whether they are active.
- (BOOL)hasSpecialLayers;

/// Whether any stored layer is an Alternative layer selected by axis rules.
///
/// Inactive Alternative layers satisfy this condition, too.
- (BOOL)hasBracketLayer;

/// Whether any stored layer is an Intermediate layer at explicit design-space coordinates.
///
/// Inactive Intermediate layers satisfy this condition, too.
- (BOOL)hasBraceLayer;

#endif

#pragma mark TempData
/// Values associated with the glyph for transient use.
///
/// Temporary data is not written to the font.
@property (nonatomic, strong) NSDictionary<NSString *, id> *tempData;

/// Sets or removes a temporary value.
///
/// Passing `nil` as the value removes the temporary value.
///
/// - Parameter value: The value to set, or `nil` to remove the temporary value.
- (void)setTempData:(nullable id)value forKey:(nonnull NSString *)key;

/// The temporary value for a key, or `nil` if no value is set.
- (nullable id)tempDataForKey:(nonnull NSString *)key;

#pragma mark Tags

/// User-defined tags for organizing and filtering the glyph.
///
/// Tags are unique and sorted.
/// They do not affect the glyph outline or font export.
/// Use this property or the tag mutation methods instead of modifying the returned set directly.
@property (nonatomic, copy) NSOrderedSet<NSString *> *tags;

/// The number of assigned tags.
- (NSUInteger)countOfTags;

/// The tag at an index, or `nil` if the index is out of range.
///
/// - Parameter idx: An index in the sorted tags.
- (nullable NSString *)objectInTagsAtIndex:(NSUInteger)idx NS_SWIFT_NAME(tag(atIndex:));

/// The index of a tag, or `NSNotFound` if the tag is not assigned.
- (NSUInteger)indexOfObjectInTags:(NSString *)tag NS_REFINED_FOR_SWIFT;

/// Adds a tag if it is not already assigned.
- (void)addTag:(NSString *)tag;

/// Removes a tag if it is assigned.
- (void)removeObjectFromTags:(NSString *)tag NS_SWIFT_NAME(removeTag(_:));

/// Removes the tag at an index.
///
/// Does nothing if the index is out of range.
///
/// - Parameter idx: An index in the sorted tags.
- (void)removeObjectFromTagsAtIndex:(NSUInteger)idx NS_SWIFT_NAME(removeTag(atIndex:));

/// An array representation of the tags for use with Cocoa bindings.
///
/// Assignment removes duplicate tags and sorts the result.
@property (nonatomic, copy) NSArray<NSString *> *tagsArray;

#pragma GSAutoCodeStart methods

#pragma GSAutoCodeEnd methods

#pragma mark - Deprecated (Glyphs 3 compatibility)

- (void)lockReadGlyph GSDeprecated("lockRead") NS_REFINED_FOR_SWIFT;
- (void)unlockReadGlyph GSDeprecated("unlockRead") NS_REFINED_FOR_SWIFT;
- (void)lockWriteGlyph GSDeprecated("lockWrite") NS_REFINED_FOR_SWIFT;
- (void)unlockWriteGlyph GSDeprecated("unlockWrite") NS_REFINED_FOR_SWIFT;
- (void)lockReadAllLayersShapes GSDeprecated("lockReadLayers") NS_REFINED_FOR_SWIFT;
- (void)unlockReadAllLayersShapes GSDeprecated("unlockReadLayers") NS_REFINED_FOR_SWIFT;
- (nullable NSDictionary *)propertyListValueFormat:(GSFormatVersion)format options:(GSSaveOptions)options GSDeprecated("propertyListValueFormat:options:error:") NS_REFINED_FOR_SWIFT;
- (NSMutableArray<NSMutableOrderedSet<NSString *> *> *)forcedLayerGroupIdsSeenLayers:(nullable NSMutableSet<NSString *> *)seenLayers GSDeprecated("forcedLayerGroupIdsSeenLayers:ignoreEmptyLayers:") NS_REFINED_FOR_SWIFT;
- (NSArray<NSMutableOrderedSet<NSString *> *> *)layerGroups:(nullable NSArray<GSInstance *> *)instances masters:(nullable NSArray<GSFontMaster *> *)masters error:(out NSError **)error GSDeprecated("layerGroupsInstances:masters:ignoreEmptyLayers:error:") NS_REFINED_FOR_SWIFT;

@end

NS_ASSUME_NONNULL_END
