//
//  GSFont.h
//  Glyphs
//
//  Created by Georg Seifert on 21.10.05.
//  Copyright 2005 schriftgestaltung.de. All rights reserved.
//
#import <Cocoa/Cocoa.h>

@class GSGlyph;
@class GSDocument;
@class GSFontMaster;
@class GSInstance;
@class GSFeature;
@class GSClass;
@class COFont;
@class MGOrderedDictionary;
@class GSCustomProperty;

#import <GlyphsCore/GSContainerProtocol.h>

/** Used to determine how to gemerate the numbers features (pnum, lnum) */
typedef NS_ENUM(uint8_t, GSFigureStyles){
	/** This is the initial state*/
	NotTested = 0,
	/** There are no figures */
	NoFigures = 1,
	/** The default figures are tabular oldstyle figures */
	tosf = 2,
	/** The default figures are proportional oldstyle figures */
	osf = 3,
	/** The default figures are tabular figures */
	tf = 4,
	/** The default figures are lining figures */
	lf = 5
};

/** This class defines the font object.

 Font info properties, that have a user interface, have proper accessors, eveything else is stored in the custom parameters
 */

@interface GSFont : NSObject <NSCoding, NSCopying, GSContainerProtocol> {
	GSDocument* __weak _parent;
	NSMutableArray* _glyphs;

	NSString* _familyName;
	NSUInteger _unitsPerEm;
	NSDate* _date;
	NSUInteger _versionMajor;
	NSUInteger _versionMinor;
	NSString* _designer, * _designerURL, * _manufacturer, * _manufacturerURL, * _copyright;

	NSMutableArray* _customParameters;
	NSMutableArray* _fontMasters;
	NSMutableArray* _features;
	NSMutableArray* _instances;
	NSMutableDictionary* _userData;
	NSMutableDictionary* _tempData;
	NSMutableDictionary* _charsCache;
	UTF32Char _lastChar;
	MGOrderedDictionary* _kerning;
	MGOrderedDictionary* _contextKerning;
	MGOrderedDictionary* _verticalKerning;
	NSUInteger _gridMain;
	NSUInteger _gridSubDivision;
	BOOL _disablesNiceNames;
	BOOL _disablesAutomaticAlignment;
	BOOL _keepAlternatesTogether;
	NSDictionary* name2Glyph;
	NSDictionary* id2Glyph;
	NSMutableArray* GlyphDictArray;
	NSMutableArray* _classes;
	NSMutableArray* _featurePrefixes;
	NSString* _tempOTFFont;
	COFont* _compositorFont;
	BOOL _disabledChanges;
	NSMutableSet* _disabledChangeKeys;
	NSDate* _lastAskedForImage;
}
//! The pointer to the document object
@property (weak, nonatomic) GSDocument* parent;

/** The undoManager of the document
 
 This is only used for font info and for adding/removing glyphs. Each glyph has it’s own undoManager.
 
 @see [GSGlyph.undoManager]([GSGlyph undoManager])
 */
@property (nonatomic, readonly) NSUndoManager* undoManager;

/** Returns the content of the font object to store it in pList.

 This is used to store the data in the .glyphs file.
 */
@property (unsafe_unretained, readonly, nonatomic) NSMutableDictionary* fontDict;

#pragma mark Info
/** @name Font Info */

//! The (family) name of the font.
@property (strong, nonatomic) NSString* familyName;

//! A note
@property (strong, nonatomic) NSString* note;

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

/// copyright
@property (strong, nonatomic) NSString* copyright;

/// designer
@property (strong, nonatomic) NSString* designer;

/// designerURL
@property (strong, nonatomic) NSString* designerURL;

/// manufacturer
@property (strong, nonatomic) NSString* manufacturer;

/// manufacturerURL
@property (strong, nonatomic) NSString* manufacturerURL;

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

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

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


/** Place for plugins to store custom 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) NSMutableDictionary* userData;

@property (nonatomic, strong) NSMutableDictionary* tempData;

/** disablesNiceNames

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

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

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

@property (nonatomic, strong) NSMutableSet* disabledChangeKeys;

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

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

 @param fontDict A dictionary
 */
- (instancetype)initWithFontDict:(NSDictionary*)fontDict;

#ifndef GLYPHS_VIEWER

- (BOOL)saveToFile:(FILE*)File error:(NSError**)error;

/** @name Font Methods */

/** Scale the hole font.

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

#endif
#pragma mark glyphs

/** @name Glyphs */

//! An Array of GSGlyph objects
@property (strong, nonatomic) NSArray* glyphs;

- (NSUInteger)count;

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

/** The glyph object located at index.

 Checks for valid index and returns nil if index is to high.
 
 @param Index An index within the bounds of the the glyphs array.
 @return a GSGlyph object.
 */
- (GSGlyph*)glyphAtIndex:(NSInteger)Index;

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

@property (nonatomic, readonly) NSDictionary* charsCache;

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

/** Returns the GSGlyph with this name.

 @warning This is a bit slow.

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

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

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

/** Adds a new glyph with this glyphName to the font
 
 @param glyphName  The new glyph name
 @param changeName If changeName is yes, the glyphName will be converted to nice-name, otherwise not.
 
 @return The new glyph.
 */
- (GSGlyph*)newGlyphWithName:(NSString*)glyphName changeName:(BOOL)changeName;

/** Calculates a names that is unique for the font
 
 @param Glyph The Glyph
 
 @return The glyph name with a .0XX suffix if the name is already in use by another glyph
 */
- (NSString*)saveNameForGlyph:(GSGlyph*)Glyph;

/** Calculates a names that is unique for the font
 
 @param GlyphName The glyph name
 
 @return The glyph name with a .0XX suffix if the name is already in use by another glyph
 */
- (NSString*)saveNameForName:(NSString*)GlyphName;

#endif

/** Returns the GSGlyph with this ID.

 @warning This is a bit slow.

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

#ifndef GLYPHS_VIEWER
/** Tests if all the glyphs are present and set to export
 
 @param GlyphNames A array of glyph names
 @return YES if all glyphs will end up in a exported font.
 @see hasGlyphs:
 @see filterKeepGlyphs:
 @see filterGlyphs:
 */
- (BOOL)keepsGlyphs:(NSArray*)GlyphNames;

/** Returns a Boolean value if the font contains the glyphs
 
 @param GlyphNames A array of glyph names
 @return YES if all glyphs are in the font.
 @see keepsGlyphs:
 @see filterKeepGlyphs:
 @see filterGlyphs:

 */
- (BOOL)hasGlyphs:(NSArray*)GlyphNames;

#endif
/** Returns all glyph names that are present and set to export
 
 @param GlyphNames A array of glyph names
 @return A list of exporting glyphs
 @see keepsGlyphs:
 @see hasGlyphs:
 @see filterGlyphs:
 */
- (NSArray*)filterKeepGlyphs:(NSArray*)GlyphNames;

/** Returns all glyph names that are present and set to export
 
 @param GlyphNames A array of glyph names
 @return A list of all glyphs that are in the font
 @see keepsGlyphs:
 @see hasGlyphs:
 @see filterKeepGlyphs:
 */
- (NSArray*)filterGlyphs:(NSArray*)GlyphNames;

/** Returns the glyph with the chars unicode.

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

/** Returns a UTF32Char for the glyph.

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

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

#ifndef GLYPHS_VIEWER

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

/** Adds the Glyph object to the font.

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

/** Adds the Glyphs object to the font.

 @param Glyphs A NSArray of GSGlyph objects.
 */
- (void)addGlyphs:(NSArray*)Glyphs;

/** Removes the Glyph from the font

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

/** Removes the Glyphs from the font

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

#endif

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

- (void)elementDidChange:(id)element;

#pragma mark fontInfoDict accessors

/** @name Custom Parameters */

/** List of custom parameters */
@property (nonatomic, retain) NSMutableArray* customParameters;

/** Returns the custom property with Name
 
 This will always return the first entry with this name. If there are multiple parameters with the same name, parse the customParameters array directly.
 
 @param key The name of the parameter
 
 @return The parameter object
 @see customValueForKey:
 */
- (GSCustomProperty*)customPropertyForKey:(NSString*)key;

/** The number of parameters in the font */
- (NSUInteger)countOfCustomParameters;

/** This returns the value of the parameter object with Name
 
 This will always return the first entry with this name. If there are multiple parameters with the same name, parse the customParameters array directly.
 
 @param key The name of the parameter
 
 @return The value of the parameter object object
 @see customPropertyForKey:
 */
- (id)customValueForKey:(NSString*)key;

/** Sets the key value pair in the font
 
 if a parameter with this name is already present, its value will be updated. Otherwise a new parameter will be added
 
 @param value a value
 @param key   The name of the parameter
 */
- (void)setCustomParameter:(id)value forKey:(NSString*)key;

/** Removes the parameter with this name from the font 

 It will only remove the first parameter with that name
 */
- (void)removeObjectFromCustomParametersForKey:(id)key;

/** Removes the parameter a theIndex 
 
 @param index The index
 */
- (void)removeObjectFromCustomParametersAtIndex:(NSUInteger)index;

/** The parameter at theIndex 
 
 @param index The index
 @return The GSCustomParameter or nil of index is out of range
 */
- (id)objectInCustomParametersAtIndex:(NSUInteger)index;

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

#pragma mark masters
/** @name Masters */

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

/** The count of masters in the font.

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

/** The master located at index

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

/** Returns the fontmaster with this id

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

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

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

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

- (void)replaceFontMasterAtIndex:(NSUInteger)theIndex withFontMaster:(GSFontMaster*)FontMaster;

/** Removes the fontmaster with this id

 @param Index The index of the FontMaster to remove.
 */
- (void)removeFontMasterAtIndex:(NSInteger)Index;

#ifndef GLYPHS_VIEWER
/** 
 Recalculate the LSB and RSB for all glyph
 
 This will not apply the metrics keys.
 */
- (void)updateMetrics;

#endif
#pragma mark instances

/** @name Instances */

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

/** The count of the Instances

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

/** The Instance at index

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

#ifndef GLYPHS_VIEWER

/** Inserts the instance at Index

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

#endif

/** Adds the Instance to the font

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

#ifndef GLYPHS_VIEWER

- (void)removeInstance:(GSInstance*)Instance;

/** Removes the Instance at Index.

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

- (void)replaceInstanceAtIndex:(NSUInteger)theIndex withInstance:(GSInstance*)Instance;

- (GSFontMaster*)interpolateFontMaster:(GSInstance*)Instance scale:(CGFloat)Scale thin:(BOOL)Thin error:(NSError**)Error;

/** Generates an instance

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

 @param Instance The Instance to use for interpolation.
 @param Error if there is a problem, it returns an NSError object (by reference) that contains details.
 @return The interpolated font, or nil if something went wrong.
 */
- (GSFont*)copyInterpolateInstance:(GSInstance*)Instance error:(NSError**)Error;
//- (GSFont*)copyInterpolateInstance: (GSInstance*) Instance ;
#endif
#pragma mark kerning

/** @name Kerning */

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

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

#ifndef GLYPHS_VIEWER

/** Compresses the kerning

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

- (void)cleanUpKerning;

#endif

/** Returns a kerning value

 @param FontMasterID The Master id
 @param LeftKey either a glyph id or a glyph group (@MM_L_XXX)
 @param RightKey either a glyph id or a glyph group (@MM_R_XXX)
 @return the kerning value
 */

- (CGFloat)kerningForFontMasterID:(id)FontMasterID LeftKey:(id)LeftKey RightKey:(id)RightKey;

/** adds a kerning value

 @param FontMasterID The Master id
 @param LeftKey either a glyph id or a glyph group (@MM_L_XXX)
 @param RightKey either a glyph id or a glyph group (@MM_R_XXX)
 @param Value the kerning value
 */
- (void)setKerningForFontMasterID:(id)FontMasterID LeftKey:(id)LeftKey RightKey:(id)RightKey Value:(CGFloat)Value;

/** removes a kerning value

 @param FontMasterID The Master id
 @param LeftKey either a glyph id or a glyph group (@MM_L_XXX)
 @param RightKey either a glyph id or a glyph group (@MM_R_XXX)
 */
- (void)removeKerningForFontMasterID:(id)FontMasterID LeftKey:(id)LeftKey RightKey:(id)RightKey;

- (CGFloat)verticalKerningForFontMasterID:(id)FontMasterID LeftKey:(id)LeftKey RightKey:(id)RightKey;

- (void)setVerticalKerningForFontMasterID:(id)FontMasterID LeftKey:(id)LeftKey RightKey:(id)RightKey Value:(CGFloat)Value;

- (void)removeVerticalKerningForFontMasterID:(id)FontMasterID LeftKey:(id)LeftKey RightKey:(id)RightKey;

- (CGFloat)contextKerningForFontMasterID:(id)FontMasterID LeftKey:(id)LeftKey RightKey:(id)RightKey before:(id)BeforeKey after:(id)AfterKey;

- (void)setContextKerningForFontMasterID:(id)FontMasterID LeftKey:(id)LeftKey RightKey:(id)RightKey Value:(CGFloat)Value before:(id)BeforeKey after:(id)AfterKey;

- (void)removeContextKerningForFontMasterID:(id)FontMasterID LeftKey:(id)LeftKey RightKey:(id)RightKey before:(id)BeforeKey after:(id)AfterKey;

#pragma mark features

/** @name Features */

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

- (NSMutableArray*)mutableFeatures;

/** The count of the features

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

/** The feature at index

 @param theIndex The index of the feature
 @return The feature located at theIndex.
 */
 - (id)featureAtIndex:(NSUInteger)theIndex;

//! Inserts the Feature at theIndex
- (void)insertFeature:(GSFeature*)Feature atIndex:(NSUInteger)theIndex;

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

//! Removes the Feature at theIndex
- (void)removeFeatureAtIndex:(NSUInteger)theIndex;

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

- (void)replaceFeatureAtIndex:(NSUInteger)theIndex withFeature:(GSFeature*)Feature;

/** Returns the feature with the name or tag.

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

#ifndef GLYPHS_VIEWER
#ifndef GLYPHS_LITE

- (BOOL)importFeatures:(NSString*)FeaturesString error:(NSError**)error;

#endif
#pragma mark Classes 


/** @name Classes */

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

- (NSMutableArray*)mutableClasses;

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

- (id)objectInClassesAtIndex:(NSUInteger)theIndex;

/** Returns the class with the name.

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

/** Adds the class */
- (void)addClass:(GSClass*)theClass;

/** Insert the Class at theIndex in the font */
- (void)insertObject:(GSClass*)Class inClassesAtIndex:(NSUInteger)theIndex;

/** Remove the class at theIndex from the font */
- (void)removeObjectFromClassesAtIndex:(NSUInteger)theIndex;

/** Removes the class from the font */
- (void)removeClass:(GSClass*)obj;

/** Replaces the the class a theIndex with Class */
- (void)replaceObjectInClassesAtIndex:(NSUInteger)theIndex withObject:(GSClass*)Class;

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

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

#pragma mark FeaturePrefixes

/** @name FeaturePrefixes */

/** An array of GSClass objects that contain additional lookups */
@property (nonatomic, strong) NSMutableArray* featurePrefixes;

/** Adds the Prefix to the font */
- (void)addFeaturePrefix:(GSClass*)Prefix;

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

/** Returns the Prefix with the name.
 
 @param Tag The prefix name.
 */
- (GSClass*)featurePrefixForTag:(NSString*)Tag;

#ifndef GLYPHS_VIEWER
/** Insert the Prefix at theIndex in the font */
- (void)insertObject:(id)Prefix inFeaturePrefixesAtIndex:(unsigned)theIndex;

/** Remove the Prefix at theIndex from the font */
- (void)removeFeaturePrefix:(GSClass*)obj;

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

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

/** Disables redrawing and updates.
 
 @warning Always call enableUpdateInterface afterwards
 */
- (void)disableUpdateInterface;

/** Reanables redrawing and updates.
 
 This only has an effect if disableUpdateInterface was called before
 */
- (void)enableUpdateInterface;

/** Check if the updating is enabled
 
 @return NO if disableUpdateInterface was called
 */
- (BOOL)isUpdateInterfaceEnabled;

- (void)updateInterface;

#pragma mark Metrics

/** The size of the grid.
 
 If it is "0", all values are stored as floats. "1" and above will ALWAYS round the coordinates.
 
 @see gridLength
 */
@property (nonatomic, assign) NSUInteger gridMain;

/** The subdivision of the grid.
 
 Divides the grid. 
 
 @see gridLength
 */
@property (nonatomic, assign) NSUInteger gridSubDivision;

/** The effective grid width.
 
 Calculated by Grid / Subdivision
 
 @return The effective size of the grid
 */
- (CGFloat)gridLength;

- (BOOL)importAFM:(NSString*)AFMString fontMaster:(GSFontMaster*)FontMaster metrics:(BOOL)doMetrics kerning:(BOOL)doKerning error:(NSError**)error;

/** Recalculates the temp font.
 
 Call it, if you changed something like the glyph set or the features and need to make sure the temp font is up to date. This is usually done automatically.
 
 @param Error if there is a problem, it returns an NSError object (by reference) that contains details.
 @return YES if successfull, NO, if not.
 @see tempOTFFont
 */
- (BOOL)compileTempFontError:(NSError**)Error;

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

#endif
@end
