//
//  GSFontMaster.h
//  Glyphs
//
//  Created by Georg Seifert on 6.9.07.
//  Copyright 2007 schriftgestaltung.de. All rights reserved.
//

#import <Cocoa/Cocoa.h>

@class GSFont;
@class GSGlyph;
@class GSLayer;
@class GSGuide;
@class GSCustomParameter;
@class GSAlignmentZone;
@class GSIndexedLookupTable;
@class GSFontInfoProperty;
@class GSInfoValue;
@class GSTTStem;
#import <GlyphsCore/GSAxis.h>
#import <GlyphsCore/GSContainerProtocol.h>
#import <GlyphsCore/GSMetric.h>
#import <GlyphsCore/GSMetricValue.h>
#import <GlyphsCore/GSUserDataProtocol.h>

NS_ASSUME_NONNULL_BEGIN

typedef NS_ENUM(int8_t, GSMetricsAlignmentType) {
	GSMetricsAlignmentNone = -1,
	GSMetricsAlignmentOnMetrics = 1,
	GSMetricsAlignmentInZone = 2,
};

/** The class defining the fontmaster object */
#ifndef GLYPHS_VIEWER
@interface GSFontMaster : NSObject <NSCoding, NSCopying, GSContainerProtocol, GSUserDataProtocol>
#else
@interface GSFontMaster : NSObject
#endif
{
	NSMutableDictionary *_userData;
	NSString *_id;

	NSMutableDictionary *_changeCount;

	NSString *_name;
	NSString *_iconName;
	uint32_t _gridMain;
	uint32_t _gridSubDivision;

#pragma GSAutoCodeStart ivars

	NSMutableArray<GSGuide *> *_guides;
	NSMutableArray<GSCustomParameter *> *_customParameters;
	NSMutableArray<GSFontInfoProperty *> *_properties;
	NSMutableDictionary *_tempData;

#pragma GSAutoCodeEnd ivars
}

@property (unsafe_unretained, nonatomic, nullable) GSFont *font;
/// @name Properties

/** the name of the FontMaster
e.g; "Regular", "Condensed", ...
*/

@property (nonatomic, strong) NSString *name;

@property (nonatomic, strong) NSString *iconName;

@property (nonatomic, readonly) NSImage *icon;

@property (nonatomic, readonly) NSString *nameUI;

@property (nonatomic, strong, nullable) NSDictionary *readBuffer;

@property (readonly) NSArray<GSMetricValue *> *axes;

@property (strong, nonatomic, nullable) GSAxisValues *axesValues;

@property (readonly, nonatomic) CGFloat *axesValuesList;

#ifndef GLYPHS_LITE
- (CGFloat)axisValueValueForId:(NSString *)aId;

- (void)setAxisValueValue:(CGFloat)value forId:(NSString *)aId;

- (void)setAxisValue:(GSMetricValue *)value forId:(NSString *)aId;

- (CGFloat)externAxisValueValueForId:(NSString *)aId;

- (void)setExternAxisValueValue:(CGFloat)value forId:(NSString *)aId;

/// For compatibility with the future.
- (CGFloat)axisInternalValueValueForId:(NSString *)ID;
/// For compatibility with the future.
- (void)setAxisInternalValueValue:(CGFloat)value forId:(NSString *)ID;
/// For compatibility with the future.
- (CGFloat)axisExternalValueValueForId:(NSString *)ID;
/// For compatibility with the future.
- (void)setAxisExternalValueValue:(CGFloat)value forId:(NSString *)ID;

#endif

/// The id
@property (copy, nonatomic) NSString *id;

@property (nonatomic) BOOL visible;

#ifndef GLYPHS_VIEWER
/** 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

#pragma mark - Metrics

- (void)addDefaultMetrics;

- (void)setDefaultMetric:(CGFloat)value forType:(GSMetricsType)type;

- (void)setDefaultMetric:(CGFloat)position overshoot:(CGFloat)over forType:(GSMetricsType)type;

- (nullable GSMetricValue *)metricValueForType:(GSMetricsType)type layer:(GSLayer *)layer;

- (nullable GSMetricValue *)defaultMetricValueForType:(GSMetricsType)type;

- (CGFloat)defaultMetricForType:(GSMetricsType)type;

- (CGFloat)metricForType:(GSMetricsType)type layer:(nullable GSLayer *)layer;

/** The default ascender.
 This is kept for compatibility, for now.
 */
@property (nonatomic, readonly) CGFloat defaultAscender;

- (CGFloat)ascenderForLayer:(GSLayer *)layer;

@property (nonatomic, readonly) CGFloat defaultDescender;

- (CGFloat)descenderForLayer:(GSLayer *)layer;

/// The capHeight.
@property (nonatomic, readonly) CGFloat defaultCapHeight;

//- (CGFloat)capHeightForLayer:(GSLayer *)layer;
/// The xHeight.
@property (nonatomic, readonly) CGFloat defaultXHeight;

- (CGFloat)xHeightForLayer:(GSLayer *)layer;

- (CGFloat)slantHeightForLayer:(nullable GSLayer *)layer;

- (CGFloat)topHeightForLayer:(GSLayer *)layer;

#pragma mark metricValues

@property (nonatomic, strong) NSDictionary<NSString *, GSMetricValue *> *metricValues;

- (GSMetricValue *)valueForMetric:(GSMetric *)metric;

- (void)setMetricValue:(GSMetricValue *)object forId:(NSString *)ID;

- (void)setMetricValue:(GSMetricValue *)object forId:(NSString *)ID notify:(BOOL)notify;

- (GSMetricValue *)setMetricPosition:(CGFloat)pos overshoot:(CGFloat)over type:(GSMetricsType)type name:(nullable GSMetricsKey)name filter:(nullable NSString *)filter;

- (NSArray<GSMetricValue *> *)metrics;

#pragma mark StemValues

@property (nonatomic, strong) NSDictionary<NSString *, GSInfoValue *> *stemValues;
#ifndef GLYPHS_VIEWER
- (GSInfoValue *)valueForStem:(GSMetric *)stem;

- (CGFloat)valueValueForStemId:(NSString *)stemId;

- (void)setStemValue:(GSInfoValue *)object forId:(NSString *)ID;

- (void)setStemValueValue:(CGFloat)value forId:(NSString *)ID;

- (NSArray<GSInfoValue *> *)stems;

- (NSArray<NSNumber *> *)stemValuesArray;

#ifndef GLYPHS_LITE
/// convenient for TT export
- (NSArray<GSTTStem *> *)ttStems;
#endif

#pragma mark NumberValues

@property (nonatomic, strong, nullable) NSDictionary<NSString *, GSInfoValue *> *numberValues;

- (GSInfoValue *)valueForNumber:(GSMetric *)number;

- (GSInfoValue *)numberValueForId:(NSString *)ID;

- (GSInfoValue *)numberValueForName:(NSString *)name;

- (CGFloat)numberValueValueForId:(NSString *)ID;

- (CGFloat)numberValueValueForName:(NSString *)name;

- (CGFloat)numberValueValueForToken:(NSString *)token;

- (void)setNumberValue:(GSInfoValue *)object forId:(NSString *)ID;

- (void)setNumberValue:(GSInfoValue *)object forName:(NSString *)name;

- (void)setNumberValueValue:(CGFloat)floatValue forId:(NSString *)ID;

- (void)setNumberValueValue:(CGFloat)floatValue forName:(NSString *)name;

- (NSArray<GSInfoValue *> *)numbers;

- (NSArray<NSNumber *> *)numberValuesArray;
#endif

#pragma mark -

/** The Italic angle
 */
@property (nonatomic) CGFloat defaultItalicAngle;

- (CGFloat)italicAngleForLayer:(GSLayer *)layer;

///// list of alignment zones
//@property (readonly, nonatomic) NSArray *alignmentZones;

- (instancetype)initFast;

//@property (strong, nonatomic) NSMutableArray *customParameters;

/// @name Initializing an Font Master

/**
 Inits with a dict.

 @param dict The property list representation
 @param formatVersion The file format version
 @return a fontmaster object
 */
- (instancetype)initWithDict:(NSDictionary *)dict format:(GSFormatVersion)formatVersion;

- (void)loadReadBuffer;

#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
 */
- (NSDictionary *)propertyListValueFormat:(GSFormatVersion)format;

- (BOOL)saveToFile:(FILE *)file format:(GSFormatVersion)formatVersion error:(out NSError **)error;

- (nullable NSArray *)blueValuesError:(out NSError **)error;

- (nullable NSArray *)otherBluesError:(out NSError **)error;

- (NSArray *)alignmentZonesForLayer:(GSLayer *)layer;

+ (GSMetricsAlignmentType)isOnMetrics:(CGFloat)position metrics:(NSArray<GSMetricValue *> *)metrics inLayer:(GSLayer *)layer;

- (BOOL)isOnMetricsLine:(NSPoint)position layer:(GSLayer *)layer;

@property (nonatomic, assign) uint32_t gridMain;

@property (nonatomic, assign) uint32_t gridSubDivision;

- (CGFloat)gridLength;

#ifndef GLYPHS_LITE

+ (CGFloat)localizedParameterValue:(NSString *)parameter glyph:(GSGlyph *)glyph;

+ (nullable NSString *)localizedParameter:(NSString *)parameter glyph:(GSGlyph *)glyph;

- (CGFloat)localizedCustomValueForKey:(NSString *)key layer:(GSLayer *)layer;

- (CGFloat)localizedCustomValueForKey:(NSString *)key script:(NSString *)script;

/// @name Other Methods
/** Scales the Font Master
Scales the vertical metrics, alignment zones and guide lines
@param scale the scale factor (1 means no scaling.)
*/
- (void)scaleBy:(CGFloat)scale;

/**
 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. Or nil to remove an existing value
 @param languageTag	The language under which the value should be stored. Defaults to `English` if nil is passed.
 */
- (void)setProperty:(NSString *)name value:(nullable NSString *)value languageTag:(nullable NSString *)languageTag;

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

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

+ (NSArray *)iconNames;

- (NSString *)defaultIconName;

/// splits the name into values that can be stored in v1 files
- (void)legacyNames:(NSString *)name weight:(NSString *_Nonnull*_Nullable)weight width:(NSString *_Nonnull*_Nullable)width custom:(NSString *_Nonnull*_Nullable)custom;

- (void)invalidateCustomParameterCache;
#endif
#endif

- (void)setReadBuffer:(NSObject *)values forKey:(NSString *)key;

#pragma mark - start auto code

#pragma GSAutoCodeStart methods

#pragma mark Guides

/// The guides.
@property (nonatomic, strong, null_resettable) NSMutableArray<GSGuide *> *guides;

#ifndef GLYPHS_VIEWER
/** The number of guides */
- (NSUInteger)countOfGuides;

- (nullable NSArray *)guidesFast;

/** Returns object at idx in guides

 @param idx The index
 @return the object at index
 */
- (nullable GSGuide *)objectInGuidesAtIndex:(NSUInteger)idx;

/** Returns the index of guide in guides

 @param guide the object
 @return the index of the object
 */
- (NSUInteger)indexOfObjectInGuides:(nonnull GSGuide *)guide;

/** Adds the guide

 @param guide the object to be added
 */
- (void)addGuide:(nonnull GSGuide *)guide;

/** Inserts the guide at index into guides

 @param guide The object to insert
 @param idx The index
 */
- (void)insertObject:(nonnull GSGuide *)guide inGuidesAtIndex:(NSUInteger)idx;

/** Removes the guide

 @param guide the object to be removed
 */
- (void)removeObjectFromGuides:(nonnull GSGuide *)guide;

/** Removes the guide at idx

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

#pragma mark CustomParameters

/// @name customParameters

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

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

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

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

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

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

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

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

/** 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:(nullable id)value forKey:(nonnull NSString *)key;

#ifndef GLYPHS_VIEWER
- (void)addCustomParameter:(nonnull GSCustomParameter *)property;

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

/** Removes the first parameter with then Name

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

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

- (void)removeObjectFromCustomParametersAtIndex:(NSUInteger)idx;

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

#pragma mark Properties
/// @name Properties

/** The properties.
 this contains (localizable) names and other font info settings
 */
@property (nonatomic, strong, null_resettable) NSMutableArray<GSFontInfoProperty *> *properties;

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

/** Returns object at idx in properties

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

/** Returns the index of property in properties

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

/** Adds the property

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

/** Inserts the property at index into properties

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

/** Removes the property

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

/** Removes the property at idx

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

#pragma mark UserData

/// @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;

#ifndef GLYPHS_VIEWER
/**
 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:(nonnull NSString *)key;
#endif

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

- (NSUInteger)countOfTempData;

/**
 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 GSAutoCodeEnd methods

@end
NS_ASSUME_NONNULL_END
