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

#import <GlyphsCore/GSAxis.h>
#import <GlyphsCore/GSBase.h>
#import <GlyphsCore/GSContainerProtocol.h>
#import <GlyphsCore/GSParametersAndPropertiesProtocol.h>
#import <GlyphsCore/GSUserDataProtocol.h>

NS_ASSUME_NONNULL_BEGIN

@class GSNameParticle;

/**
 Key for single instance type.
 */
extern NSString *const GSInstanceTypeSingleKey;

/**
 Key for variable instance type.
 */
extern NSString *const GSInstanceTypeVariableKey;

/**
 Key for static instance type.
 */
extern NSString *const GSInstanceTypeStaticKey;

/**
 Key for icon instance type.
 */
extern NSString *const GSInstanceTypeIconKey;

/**
 Key for listing instance type.
 */
extern NSString *const GSInstanceTypeParticlesKey;

extern NSString *const GSInstanceAxisIdKey;
extern NSString *const GSInstanceAxisTagKey;
/**
 Enum defining the types of instances.
 */
typedef NS_ENUM(uint8_t, GSInstanceType) {
	/// Single instance type.
	GSInstanceTypeSingle = 0,
	/// Variable instance type.
	GSInstanceTypeVariable = 1,
	/// Static instance type.
	GSInstanceTypeStatic = 2,
	/// Icon instance type.
	GSInstanceTypeIcon = 3,
	/// Particles type.
	GSInstanceTypeParticle = 4,
};

@class GSFont;
@class GSCustomParameter;
@class GSInfoProperty;
#ifndef GLYPHS_VIEWER
@class GSInfoValueLocalized;
#endif
@class GSInfoValue;
@class GSIconPreset;
#ifndef GLYPHS_LITE
@class GSInterpolationFontProxy;
#endif

/** The class defining the instance object */
#ifndef GLYPHS_LITE
@interface GSInstance : NSObject <NSCoding, NSCopying, GSContainerProtocol, GSParametersAndPropertiesProtocol, GSUserDataProtocol>
#else
@interface GSInstance : NSObject <NSCoding, NSCopying, GSContainerProtocol, GSParametersAndPropertiesProtocol>
#endif
{
	NSImage *_image;
	BOOL _isLoadingImage;
}

- (instancetype)initFast;

#ifndef GLYPHS_VIEWER
/**
 Initializes a new instance of the GSInstance class with a type.

 @param type The type of the instance.
 @return A new instance of the GSInstance class.
 */
- (instancetype)initWithType:(GSInstanceType)type;
#endif

/**
 Initializes a new instance of the GSInstance class with a type name.

 @param typeName The type name of the instance.
 @return A new instance of the GSInstance class.
 */
- (instancetype)initWithTypeName:(NSString *)typeName;

/**
 Initializes a new instance of the GSInstance class with a dictionary and format version.

 @param dict The dictionary to initialize with.
 @param parent The parent container.
 @param formatVersion The format version to initialize with.
 @return A new instance of the GSInstance class.
 */
- (instancetype)initWithDict:(NSDictionary *)dict container:(nullable id)parent format:(GSFormatVersion)formatVersion;

/** Reference to the containing font */
@property (weak, nonatomic, nullable) GSFont *font;

/// A unique identifier for the instance that does not change when other properties such as the same are changed.
///
/// This identifier is written starting from Glyphs file format version 4.
@property (strong, nonatomic) NSString *id;

/// The type of the instance.
@property (assign) GSInstanceType type;

/// The name of the instance type.
@property (readonly) NSString *typeName;

/// The read buffer dictionary.
@property (nonatomic, strong) NSDictionary *readBuffer;

/// The style to use as the regular for this style.
/// If styleName is `Medium`, you could link to `Light`. So this instance becomes the Bold style for the Light.
@property (copy, nonatomic) NSString *linkStyle;

#pragma mark Axes

/// The axis values of the instance.
@property (strong, nonatomic) GSAxisValues *axesValues;

#ifndef GLYPHS_LITE
/// A list of the axis values.
@property (readonly, nonatomic, nullable) CGFloat *axesValuesList;

/**
 Returns the axis value for a specific ID.

 @param ID The ID of the axis.
 @return The axis value, or nil if not found.
 */
- (nullable GSMetricStore *)axisValueForId:(NSString *)ID;

/**
 Sets the axis value for a specific ID.

 @param value The axis value to set.
 @param ID The ID of the axis.
 */
- (void)setAxisValue:(nullable GSMetricStore *)value forId:(NSString *)ID;

/**
 Sets the axis value quickly without copying data for a specific ID.

 @param value The axis value to set.
 @param ID The ID of the axis.
 */
- (void)setAxisValueFast:(nullable GSMetricStore *)value forId:(NSString *)ID;

#ifndef GLYPHS_VIEWER
/**
 Returns the internal axis value for a specific ID.

 @param ID The ID of the axis.
 @return The internal axis value.
 */
- (CGFloat)axisInternalValueValueForId:(NSString *)ID;

/**
 Sets the internal axis value for a specific ID.

 @param value The internal axis value to set.
 @param ID The ID of the axis.
 */
- (void)setAxisInternalValueValue:(CGFloat)value forId:(NSString *)ID;

/**
 Returns the axis value for a specific ID. (Deprecated)

 @param ID The ID of the axis.
 @return The axis value.
 */
- (CGFloat)axisValueValueForId:(NSString *)ID GSDeprecated("axisInternalValueValueForId:");

/**
 Sets the axis value for a specific ID. (Deprecated)

 @param value The axis value to set.
 @param ID The ID of the axis.
 */
- (void)setAxisValueValue:(CGFloat)value forId:(NSString *)ID GSDeprecated("setAxisInternalValueValue:forId:");

/**
 Returns the external axis value for a specific ID.

 @param ID The ID of the axis.
 @return The external axis value.
 */
- (CGFloat)axisExternalValueValueForId:(NSString *)ID;

/**
 Sets the external axis value for a specific ID.

 @param value The external axis value to set.
 @param ID The ID of the axis.
 */
- (void)setAxisExternalValueValue:(CGFloat)value forId:(NSString *)ID;
#endif
#endif

#ifndef GLYPHS_VIEWER
#ifdef LIBCORE
/// The interpolation weight position.
@property (nonatomic) float interpolationWeight;

/// The interpolation width position.
@property (nonatomic) float interpolationWidth;

/// The interpolation custom position.
@property (nonatomic) float interpolationCustom;

/// The interpolation custom position 1.
@property (nonatomic) float interpolationCustom1;

/// The interpolation custom position 2.
@property (nonatomic) float interpolationCustom2;

/// The interpolation custom position 3.
@property (nonatomic) float interpolationCustom3;
#endif
#endif

#ifndef GLYPHS_LITE
/// The interpolated font proxy.
- (nullable GSInterpolationFontProxy *)interpolatedFont:(out NSError **)error;
#ifndef GLYPHS_VIEWER
/**
 Returns the coordinate for a specific axis index.

 @param axisIndex The index of the axis.
 @return The coordinate.
 */
- (CGFloat)coordinateForAxisIndex:(NSUInteger)axisIndex;
#endif
#endif

/// The weight class UI string (e.g. Regular or Bold).
@property (readonly, nonatomic, nullable) NSString *weightClassUI;

/// The actual weight class value as set by the weightClass or custom parameter "weightClass".
@property (nonatomic) uint16_t weightClassValue;

/// The width class UI string (e.g. Medium).
@property (strong, nonatomic, nullable) NSString *widthClassUI;

/// The actual width class value as set by the widthClass.
@property (nonatomic) uint16_t widthClassValue;

/// The style linking italic bit.
@property (nonatomic) BOOL isItalic;

/// The style linking bold bit.
@property (nonatomic) BOOL isBold;

#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 dictionary format.
 @return The property list dictionary.
 */
- (nullable NSDictionary *)propertyListValueFormat:(GSFormatVersion)format error:(out NSError **)error;
#endif

/**
 Performs post-read operations.

 @param error A pointer to an NSError object to store any error that occurs.
 @param formatVersion The format version.
 @return YES if successful, NO otherwise.
 */
- (BOOL)postRead:(out NSError **)error format:(GSFormatVersion)formatVersion;

/// The user data dictionary.
@property (strong, nonatomic, nullable) NSMutableDictionary *userData;

/**
 Checks if the instance is equal to another instance.

 @param object The other instance to compare against.
 @return YES if the instances are equal, NO otherwise.
 */
- (BOOL)isEqualToInstance:(GSInstance *)object;

#ifndef GLYPHS_VIEWER
/**
 Saves the instance to a file with the specified format version.

 @param file The file to save to.
 @param formatVersion The format version to use.
 @param error A pointer to an NSError object to store any error that occurs.
 @return YES if the save operation is successful, NO otherwise.
 */
- (BOOL)saveToFile:(FILE *)file format:(GSFormatVersion)formatVersion context:(GSSaveContext *)context error:(out NSError **)error;
#endif

/** A dictionary that contains the interpolation coefficients for each master.
 This is automatically updated if you change interpolationWeight, interpolationWidth, interpolationCustom.
 It contains FontMaster IDs as keys and coefficients for that master as values.
 Or, you can set it manually if you set manualInterpolation to true. There is no UI for this, so you need to do that with a script.
 */
@property (strong, nonatomic, nullable) NSDictionary *instanceInterpolations;

#ifndef GLYPHS_LITE
/** Disables automatic calculation of instanceInterpolations
 This allows manually setting instanceInterpolations.
 */
@property (nonatomic) BOOL manualInterpolation;

/**
 Returns the instance interpolations with updates.

 @param updateKVO A boolean indicating whether to update KVO.
 @return The instance interpolations dictionary.
 */
- (nullable NSDictionary *)instanceInterpolationsWithUpdates:(BOOL)updateKVO;

/** Call it if you have made changes to the instance to force an update of instanceInterpolations. */
- (void)updateInterpolationValues;

/**
 Returns the filtered masters for the specified font.

 @param font The font to filter masters for.
 @param error A pointer to an NSError object to store any error that occurs.
 @return An array of filtered masters.
 */
- (nullable NSMutableArray *)filteredMasters:(GSFont *)font error:(out NSError **)error;

/**
 Returns the instance key.

 @return The instance key.
 */
- (NSString *)instanceKey;
#endif

/**
 Returns an array of allowed property keys.

 @return An array of allowed property keys.
 */
+ (NSArray *)allowedPropertyKeys;

#ifndef GLYPHS_VIEWER
#ifndef GLYPHS_LITE
/**
 Scales the instance object.

 @param scale The scale value.
 */
- (void)scaleBy:(CGFloat)scale;
#endif
#endif

/**
 Returns the outline format.

 @return The outline format.
 */
- (GSOutlineFormat)outlineFormat;

#ifndef GLYPHS_VIEWER
/**
 Returns the file name with the specified format.

 @param format The format to use for the file name.
 @param error A pointer to an NSError object to store any error that occurs.
 @return The file name, or nil if an error occurs.
 */
- (nullable NSString *)fileName:(GSFontFormat)format error:(out NSError **)error;

/**
 Returns the file name with the specified format. It includes the "Export Folder" part.
 @param format The format to use for the file name.
 @param error A pointer to an NSError object to store any error that occurs.
 @return The file name, or nil if an error occurs.
 */
- (nullable NSString *)finalPath:(NSString *)format error:(NSError **)error;

/**
 Returns the preferred family names.

 @param error A pointer to an NSError object to store any error that occurs.
 @return The preferred family names.
 */
- (nullable GSInfoValueLocalized *)preferredFamilyNames:(out NSError **)error;

/**
 Returns the preferred subfamily names.

 @param error A pointer to an NSError object to store any error that occurs.
 @return The preferred subfamily names.
 */
- (GSInfoValueLocalized *)preferredSubfamilyNames:(out NSError **)error;

/**
 Returns the style map family names.

 @param error A pointer to an NSError object to store any error that occurs.
 @return The style map family names.
 */
- (GSInfoValueLocalized *)styleMapFamilyNames:(out NSError **)error;

/**
 Returns the style map style names.

 @param error A pointer to an NSError object to store any error that occurs.
 @return The style map style names.
 */
- (GSInfoValueLocalized *)styleMapStyleNames:(out NSError **)error;

/**
 Returns the PostScript name prefix.

 @param error A pointer to an NSError object to store any error that occurs.
 @return The PostScript name prefix.
 */
- (nullable NSString *)postScriptNamePrefix:(out NSError **)error;

/**
 Returns the font name.

 @param error A pointer to an NSError object to store any error that occurs.
 @return The font name.
 */
- (NSString *)fontName:(out NSError **)error;

/**
 Returns the full name.

 @param error A pointer to an NSError object to store any error that occurs.
 @return The full name.
 */
- (NSString *)fullName:(out NSError **)error;

/**
 Returns the name for the UI.

 @return The name for the UI.
 */
- (NSString *)nameUI;

/**
 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 `GSInfoValue` 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:(GSPropertyName)name value:(nullable NSString *)value languageTag:(nullable NSString *)languageTag;

#ifndef GLYPHS_LITE
/**
 Returns the property for the specified name and language tag.

 @param name The name of the property.
 @param languageTag The language tag.
 @return The property value, or nil if not found.
 */
- (nullable GSInfoValue *)propertyForName:(GSPropertyName)name languageTag:(NSString *)languageTag;
#endif
/**
 Returns the property for the specified name.

 @param name The name of the property.
 @return The property, or nil if not found.
 */
- (nullable GSInfoProperty *)propertyForName:(GSPropertyName)name;

/**
 Returns the default property for the specified name.

 @param name The name of the property.
 @return The default property, or nil if not found.
 */
- (nullable NSString *)defaultPropertyForName:(GSPropertyName)name;

/**
 Sets the default property for the specified name.

 @param name The name of the property.
 @param value The value to set.
 */
- (void)setDefaultProperty:(GSPropertyName)name value:(id)value;

/**
 Invalidates the custom parameter cache.
 */
- (void)invalidateCustomParameterCache;

#pragma mark TempData

/// A dictionary that stores temporary 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 previously set data.

 @param value The object to set, or nil to remove the data.
 @param key The key.
 */
- (void)setTempData:(nullable id)value forKey:(nonnull NSString *)key;

/**
 Returns the value for the specified key in tempData.

 @param key The key.
 @return The value, or nil if not found.
 */
- (nullable id)tempDataForKey:(nonnull NSString *)key;

/// An array of icon presets.
@property (strong, nonatomic) NSArray<GSIconPreset *> *iconPresets;

#ifndef GLYPHS_LITE
/**
 Returns the index of the specified icon preset in iconPresets.

 @param iconPreset The icon preset.
 @return The index of the icon preset.
 */
- (NSUInteger)indexOfObjectInIconPresets:(GSIconPreset *)iconPreset;

/// the name particle.
@property (strong, nonatomic) NSDictionary<NSString *, NSArray <GSNameParticle *> *> *nameParticles;

- (void)addNameParticle:(GSNameParticle *)nameParticle forAxisId:(NSString *)axisId;

- (void)removeNameParticle:(GSNameParticle *)nameParticle forAxisId:(NSString *)axisId;

#endif
#endif

#pragma GSAutoCodeStart methods

#pragma mark CustomParameters

/// @name customParameters

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

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

/**
 Returns the custom parameter object at the specified index.

 @param idx The index.
 @return The custom parameter object.
 */
- (nullable GSCustomParameter *)objectInCustomParametersAtIndex:(NSUInteger)idx;

/**
 Returns the boolean value of the custom parameter for the specified key, or the default value if not found.

 @param key The key.
 @param defaultValue The default value.
 @return The boolean value of the custom parameter, or the default value.
 */
- (BOOL)customBoolValueForKey:(NSString *)key defaultValue:(BOOL)defaultValue;

/**
 Returns the boolean value of the custom parameter for the specified key.

 @param key The key.
 @return The boolean value of the custom parameter.
 */
- (BOOL)customBoolValueForKey:(NSString *)key;

/**
 Returns the color value of the custom parameter for the specified key.

 @param key The key.
 @return The color value of the custom parameter.
 */
- (nullable id)customColorValueForKey:(NSString *)key;

/// Returns the value of the custom parameter for the specified key.
- (nullable id)customValueForKey:(NSString *)key;

/// Returns the custom parameter object for the specified key.
- (nullable GSCustomParameter *)customParameterForKey:(NSString *)key;

/// Returns the active custom parameter object for the specified key.
- (nullable GSCustomParameter *)customParameterActiveForKey:(NSString *)key;

/**
 Sets the value for the custom parameter with the specified key.

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

#ifndef GLYPHS_VIEWER
/**
 Adds a custom parameter.

 @param property The custom parameter to add.
 */
- (void)addCustomParameter:(GSCustomParameter *)property;

/**
 Removes the specified custom parameter.

 @param customParameter The custom parameter to remove.
 */
- (void)removeObjectFromCustomParameters:(GSCustomParameter *)customParameter;

/**
 Removes the first custom parameter with the specified key.

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

/**
 Inserts a custom parameter at the specified index.

 @param customParameter The custom parameter to insert.
 @param idx The index.
 */
- (void)insertObject:(GSCustomParameter *)customParameter inCustomParametersAtIndex:(NSUInteger)idx;

/**
 Removes the custom parameter at the specified index.

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

/**
 Replaces the custom parameter at the specified index with a new custom parameter.

 @param idx The index.
 @param customParameter The new custom parameter.
 */
- (void)replaceObjectInCustomParametersAtIndex:(NSUInteger)idx withObject:(GSCustomParameter *)customParameter;
#endif

/// Indicates if the instance should be exported.
@property (nonatomic) BOOL exports;

/// The name of the instance. This is used as the style name.
@property (nonatomic, strong, null_resettable) NSString *name;

#pragma mark Properties
#ifndef GLYPHS_VIEWER
/// A list of property objects.
@property (nonatomic, strong, null_resettable) NSMutableArray<GSInfoProperty *> *properties;

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

/**
 Returns the property object at the specified index.

 @param idx The index.
 @return The property object.
 */
- (nullable GSInfoProperty *)objectInPropertiesAtIndex:(NSUInteger)idx;

/**
 Returns the index of the specified property in properties.

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

/**
 Adds a property object to the properties array.

 @param property The property object to add.
 */
- (void)addProperty:(GSInfoProperty *)property;

/**
 Inserts a property object at the specified index in the properties array.

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

/**
 Removes a property object from the properties array.

 @param property The property object to remove.
 */
- (void)removeObjectFromProperties:(GSInfoProperty *)property;

/**
 Removes the property object at the specified index from the properties array.

 @param idx The index of the property object to remove.
 */
- (void)removeObjectFromPropertiesAtIndex:(NSUInteger)idx;
#endif

/**
 Indicates if the instance is visible in Preview > Show All instances.
 */
@property (nonatomic) BOOL visible;

#pragma GSAutoCodeEnd methods
@end

NS_ASSUME_NONNULL_END
