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

#import <Cocoa/Cocoa.h>
#import <GlyphsCore/GSAxis.h>
#import <GlyphsCore/GSContainerProtocol.h>
#import <GlyphsCore/GSUserDataProtocol.h>

NS_ASSUME_NONNULL_BEGIN

extern NSString *const GSInstanceTypeSingleName;
extern NSString *const GSInstanceTypeVariableName;
extern NSString *const GSInstanceTypeIconName;

typedef NS_ENUM(NSInteger, GSInstanceType) {
	GSInstanceTypeSingle,
	GSInstanceTypeVariable,
	GSInstanceTypeIcon
};

@class GSFont;
@class GSCustomParameter;
@class GSFontInfoProperty;
@class GSFontInfoValueLocalized;
#ifndef GLYPHS_LITE
@class GSInterpolationFontProxy;
@class GSFontInfoValue;
#endif

/** The class defining the instance object
 */

@interface GSInstance : NSObject <NSCoding, NSCopying, GSContainerProtocol, GSUserDataProtocol> {
	GSFont *__unsafe_unretained _font;
	NSString *_linkStyle;
	BOOL _isItalic;
	BOOL _isBold;
#ifndef GLYPHS_LITE
	BOOL _manualInterpolation;
	GSInterpolationFontProxy *_interpolatedFont;
	NSImage *_image;
	BOOL _isLoadingImage;
#endif

#pragma GSAutoCodeStart ivars

	NSMutableArray<GSCustomParameter *> *_customParameters;
	BOOL _exports;
	NSString *_name;
	NSMutableArray<GSFontInfoProperty *> *_properties;
	BOOL _visible;

#pragma GSAutoCodeEnd ivars
}

- (instancetype)initWithType:(GSInstanceType)type;

- (instancetype)initWithTypeName:(NSString *)typeName;

- (instancetype)initWithDict:(NSDictionary *)dict container:(id)parent format:(GSFormatVersion)formatVersion;

/** reference to the containing font */
@property (unsafe_unretained, nonatomic, nullable) GSFont *font;

@property (readonly) GSInstanceType type;

@property (readonly) NSString *typeName;

@property (nonatomic, strong) NSDictionary *readBuffer;

/// @name info

/** The style to use as a the regular for this style.

 if styleName is `Medium`, you could link to `Light`. So this instance becomes the Bold stil for the Light.
 */
@property (copy, nonatomic) NSString *linkStyle;

#pragma mark Axes

@property (strong, nonatomic) GSAxisValues *axesValues;

@property (readonly, nonatomic) CGFloat *axesValuesList;
#ifndef GLYPHS_VIEWER
- (CGFloat)axisValueValueForId:(NSString *)aId;

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

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

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

- (void)setAxisValue:(GSMetricValue *)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;

#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
@property (nonatomic) float interpolationCustom1;
/// The interpolation Custom position
@property (nonatomic) float interpolationCustom2;

@property (nonatomic) float interpolationCustom3;
#endif
#endif
#ifndef GLYPHS_LITE
@property (nonatomic, readonly, nullable) GSInterpolationFontProxy *interpolatedFont;
#ifndef GLYPHS_VIEWER
#ifndef LIBCORE
- (CGFloat)coordinateForAxisIndex:(NSUInteger)axisIndex;
#endif
#endif
#endif

/** Weight Class

 e.g. Regular or Bold
 */
@property (readonly, nonatomic, nullable) NSString *weightClassUI;

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

/** Width Class

 e.g. Medium (normal)
 */
@property (strong, nonatomic, nullable) NSString *widthClassUI;

/// returns the actual 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 dict
 */
- (nullable NSDictionary *)propertyListValueFormat:(GSFormatVersion)format;
#endif

- (BOOL)postRead:(NSError **)error format:(GSFormatVersion)formatVersion;

@property (strong, nonatomic, nullable) NSMutableDictionary *userData;

- (BOOL)isEqualToInstance:(GSInstance *)object;

#ifndef GLYPHS_VIEWER
- (BOOL)saveToFile:(FILE *)file format:(GSFormatVersion)formatVersion error:(NSError **)error;
#endif
/** A dict 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 coeffients 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 to manually setting instanceInterpolations.
 */
@property (nonatomic) BOOL manualInterpolation;

#ifndef GLYPHS_VIEWER
- (nullable NSDictionary *)instanceInterpolationsWithUpdates:(BOOL)updateKVO;

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

- (nullable NSMutableArray *)filteredMasters:(GSFont *)font error:(NSError **)error;

#endif

- (NSString *)instanceKey;

+ (NSArray *)allowedPropertyKeys;

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

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

- (GSOutlineFormat)outlineFormat;

- (NSString *)fileName;

- (nullable NSString *)fileName:(NSString *)format error:(NSError **)error;

// including the "Export Folder" part.
- (nullable NSString *)finalPath:(NSString *)format error:(NSError **)error;

- (GSFontInfoValueLocalized *)preferredFamilyNames:(NSError **)error;
- (GSFontInfoValueLocalized *)preferredSubfamilyNames:(NSError **)error;
// - (NSString *)macStyle;
- (GSFontInfoValueLocalized *)styleMapFamilyNames:(NSError **)error;
- (GSFontInfoValueLocalized *)styleMapStyleNames:(NSError **)error;

- (NSString *)postScriptNamePrefix:(out NSError **)error;

- (NSString *)fontName:(NSError **)error;
- (NSString *)fullName:(NSError **)error;

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

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

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

- (void)invalidateCustomParameterCache;

#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 GSAutoCodeStart methods

#pragma mark CustomParameters

/// @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 defaultValue:(BOOL)defaultValue;

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

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

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

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

- (GSCustomParameter *)customParameterActiveForKey:(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:(id)value forKey:(NSString *)key;

#ifndef GLYPHS_VIEWER
- (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

/**
If it should be exported.
 */
@property (nonatomic) BOOL exports;

/**
The Instances name

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

#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;

/** 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;
/**
If it instance is visible in Preview > Show All instances
 */
@property (nonatomic) BOOL visible;

#pragma GSAutoCodeEnd methods
@end

NS_ASSUME_NONNULL_END
