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

#import <Cocoa/Cocoa.h>

typedef struct _GSGlyphMetrics {
	CGFloat width;
	CGFloat ascender;
	CGFloat capHeight;
	CGFloat descender;
	CGFloat xHeight;
	CGFloat italicAngle;
} GSGlyphMetrics;


@class GSGlyph;
@class GSPath;
@class GSNode;
//@class GSFontMaster;
@class GSAnchor;
@class GSComponent;
@class GSHint;
@class GSElement;
@class GSBackgroundLayer;
@class GSBackgroundImage;
@class GSGuideLine;

/*! \brief GSLayer: The class defining the layer object
 \ingroup common
 This class defines the layer object.
 */
@interface GSLayer : NSObject <NSCoding, NSCopying> {
	NSString				*name;

	NSMutableArray			*_paths;
	NSMutableDictionary		*_anchors;
	NSMutableArray			*_components;
	GSBackgroundLayer		*_background;
	NSMutableDictionary		*_userData;
	NSMutableArray			*_selection;
	GSGlyph					*parent;
	NSBezierPath			*_bezierPath;
	NSBezierPath			*_selectionPath;

	NSString				*layerId;
	NSString				*associatedMasterId;
	NSDictionary			*_kerning;
	NSMutableArray			*_hints;
	BOOL					looked;
	GSBackgroundImage		*backgroundImage;
	NSMutableArray			*_guideLines;
	BOOL					disableUpdates;
	BOOL					hasDisabledUpdates;
	NSMutableDictionary		*changeCount;
//	NSMutableArray			*_strokes;

	CGFloat					_a;
	CGFloat					_b;
	CGFloat					_penAngle;
//@public
	CGFloat					_LSB, _RSB, width;
	//NSInteger				updateCount;
	BOOL					_hasAlignedWidth;
}

@property(readonly) id content;
//! A Pointer to the containing GSGlyph object
@property(assign, nonatomic) GSGlyph* parent;

//! The title of the layer.
/**
 This may be the Title of the Associates Font Master or a date (to keep track of history)
 */
@property(retain, nonatomic) NSString * name;
//! An array of GSPath objects.
@property(/*nonatomic,*/ retain, nonatomic) NSArray* paths;
//! An array of GSAnchor objects.
@property(retain, nonatomic) NSDictionary* anchors;
//! An array of GSComponents objects.
@property(retain, nonatomic) NSArray* components;
@property(retain, nonatomic) GSLayer * background;
@property(retain, nonatomic) GSBackgroundImage * backgroundImage;
@property(retain, nonatomic) NSArray * guideLines; 
//! A dict where custom plugins can store data. It will be stored in the document file.
/**
 The stored object have to conform to the NSCoding protocol.
 */
@property(retain, nonatomic) NSMutableDictionary * userData;
//! An array of GSElement objects.
/**
 all currently selected elements, otherwise nil.
 */
@property(retain, nonatomic) NSMutableArray* selection;

////! The currently selected GSNode object.
///**
// @return The curently selected node if only one is selected, otherwise nil.
// \see selNodes
// */
////@property(retain) id selectedElement;

//! The LSB
/**
 \see RSB
 \see width
 */
@property CGFloat LSB;
//! The RSB
/**
 \see LSB
 \see width
 */
@property CGFloat RSB;
//! The width
/**
 \see LSB
 \see RSB
 */
@property(nonatomic) CGFloat width;
@property(nonatomic, assign) BOOL hasAlignedWidth;
@property(nonatomic, assign) NSString * leftMetricsKey;
@property(nonatomic, assign) NSString * rightMetricsKey;
//! Returns the bezierpath for the layer.
@property(nonatomic, retain) NSBezierPath* bezierPath;
@property(nonatomic, retain) NSBezierPath* selectionPath;
//! Returns the content of the layer to store in pList.
@property(readonly) NSDictionary* layerDict;
//! The layer key is used to access the layer in the glyphs layer dictionary. 
/**
 For master layers this should be the id of the FontMaster.
 It could look like this: "FBCA074D-FCF3-427E-A700-7E318A949AE5"
 */
@property(retain, nonatomic) NSString * layerId;
//! The associatedMasterId is used to connect a layer which is not a master layer with a FontMaster.
/**
 This is needed for copies of layers (e.g. for different versions) to access vertical metrics stored in the FontMaster.
 It could look like this: "FBCA074D-FCF3-427E-A700-7E318A949AE5"
 */
@property(retain, nonatomic) NSString * associatedMasterId;
//! A dummy property to support KVO.
@property(readonly, nonatomic) NSDictionary* kerning;
//! if looked, no user changes are allowed.
/**
 this is mostly to diable accented Glyphs to be edited.
 */
@property BOOL					looked;
//! the array of hints.
@property (retain) NSArray		*hints;
@property (readonly) GSNode		*selNode;
@property (nonatomic) BOOL		disableUpdates;
//@property (retain, nonatomic) NSArray		*strokes;
//! initialises a layer with a dictionary loaded from a pList.
/**
 @param layerDict A dictionary
 */
- (id) initWithLayerDict:(NSDictionary *) layerDict;
- (BOOL) saveToFile:(FILE*) File error:(NSError**) error ;
//! Returns a string to easily compare the paths of the layers.
/**
 The string has a letter for each node. 
 Offcurve = o
 Curve = c
 Line = l
 @return A NSString.
 */
- (NSString*) compareString ;
- (GSNode *) nodeAtPoint:(NSPoint) aPoint excludeNode:(GSNode *) Exclude tollerance: (CGFloat) tolerance ;
#pragma mark Paths

//! Inserts Path into the paths array at the location specified by Index.
/**
 @param Path The path object
 @param Index An index within the bounds of the the pahts array.
 */
- (void)insertPath:(GSPath *)Path atIndex:(NSInteger) Index ;

//! Removes the path at index.
/**
 @param Index The index from which to remove the path.
 \see insertPath:atIndex:
 */
- (void)removePathAtIndex:(NSInteger) Index ;

//! Add the path to the layer.
/**
 @param Path The Path to add.
 */
- (void) addPath:(GSPath*) Path;

//! Removes the path from the layer.
/**
 This is necessary for scripting over Distributed Object (JSTalk)
 @param Path The Path to remove from the layer.
 */
- (void) removePath:(GSPath*) Path;
- (void) replacePathAtIndex:(NSUInteger)theIndex withPath:(GSPath*) Path;
- (GSNode*) connectPathsWithNode:(GSNode*) moveNode andNode: (GSNode*) overNode ;
//! returnes the node before the opening.
- (GSNode*) dividePathAtNode:(GSNode*) Node;
- (void) connectAllOpenPaths ;
//! Is called from element objects (anchors, components) if it has changed.
- (void) elementDidChange:(GSElement*) Element;
//! Returns the count of paths in the layer.
/**
 @return The count of paths in the layer.
 */
- (NSUInteger) pathCount;
//! Returns the path loacated at index.
/*
 @param Index An index within the bounds of the the paths array.
 @return A GSPath object.
 */
- (GSPath*) pathAtIndex:(NSInteger) Index ;
//! Returns the layer loacated at index.
/*
 @param Path An path object.
 @return The Index of Path in the paths array. If path is not in the paths array it returns NSNotFound.
 */
- (NSInteger) indexOfPath:(GSPath*) Path ;
- (GSNode*) nodeAtIndexPath:(NSIndexPath*) IndexPath ;
- (NSIndexPath*) indexPathOfNode:(GSNode*) Node ;
#pragma mark Anchor
- (NSInteger) anchorCount ;
//! Adds the Anchor to the Layer.
/**
 @param Anchor A Anchor.
 */
- (void) addAnchor:(GSAnchor*) Anchor;

//! Adds a copy of the Anchor to the Layer.
/**
 @param Anchor A Anchor.
 @return A reference to the copy.
 */
//- (GSAnchor*) addAnchorCopy:(GSAnchor*) Anchor;

//! Removes the Anchor From the Layer.
/**
 @param Anchor A Anchor.
 */
- (void) removeAnchor:(GSAnchor*) Anchor;
//! Removes the Anchor with the name /a AnchorName from the Layer.
/**
 @param AnchorName A Anchor name.
 */
- (void) removeAnchorWithName:(NSString*) AnchorName;
- (GSAnchor*) anchorForName: (id) Name;
- (void) anchorChangedName:(GSAnchor*) Anchor;
#pragma mark Components
- (NSUInteger) componentCount ;
//! Returns the component loacated at theIndex.
/*
 @param theIndex An index within the bounds of the the paths array.
 @return A GSComponent object.
 */
- (GSComponent*) componentAtIndex: (NSUInteger) theIndex ;

//! Adds the Component to the Layer.
/**
 @param Component A Component.
 */
- (void) addComponent:(GSComponent*) Component ;


- (void) insertComponent:(GSComponent *)aComponent atIndex:(NSUInteger)Index;
//! Removes the Component from the Layer.
/**
 @param Component A Component name.
 */
- (void) removeComponent:(GSComponent*) Component ;
- (void) removeComponentAtIndex:(NSInteger) Index ;
//! Helper function to fix component position.
/**
 Call this every time you need to access the component.
 If the first component is a letter and the second is a accent, the Letter is placed at the origin, the width of the glyphs is copied from the referenced Glyph. If it find corresponding anchors it alignes the accents on it.
 */
- (void) alignComponents ;
- (GSLayer*) copyDecomposedLayer ;
#pragma mark BackgroundImage

//! Add the image at the given URL.
/**
 It does some checking, if it is a Image.
 @param URL The Image URL
 */
- (void) addBackgroundImageWithURL: (NSURL*) URL ; 

#pragma mark GuideLines

- (NSArray *) guideLines ;
- (NSUInteger) guideLineCount ;

//! Returns the guideline loacated at theIndex.
/*
 @param theIndex An index within the bounds of the the guidelines array.
 @return A GSComponent object.
 */
- (id) guideLineAtIndex:(NSUInteger)theIndex ;
- (void) getGuideLines:(id *)objsPtr range:(NSRange)range ;
- (void) insertGuideLine:(GSGuideLine*)obj atIndex:(NSUInteger)theIndex ;
- (void) addGuideLine: (GSGuideLine*) GuideLine ;
- (void) removeGuideLine: (GSGuideLine*) GuideLine ;
- (void) removeGuideLineAtIndex:(NSUInteger)theIndex ;
- (void) replaceGuideLineAtIndex_:(NSUInteger)theIndex withGuideLine:(GSGuideLine*)GuideLine ;

#pragma mark Hints
//! Adds the Hint to the Layer.
/**
 @param Hint A Hint.
 */
- (void) addHint:(GSHint*) Hint ;

//! Adds a copy of the Hint to the Layer.
/**
 @param Hint A Hint.
 @return The copied Hint.
 */
//- (GSHint*) addHintCopy:(GSHint*) Hint ;

- (GSHint*) hintAtIndex:(NSUInteger) theIndex ;
- (void) insertHint:(GSHint*) Hint atIndex:(NSUInteger)theIndex;
//! Removes the Hint from the Layer.
/**
 @param Hint A Hint.
 */
- (void) removeHint:(GSHint*) Hint ;

#pragma mark Kerning
//! Return the kerning value for the sequence LeftLayer > self.
/**
 This checks if there is class kerning or exception.
 @param LeftLayer
 @return The kerning value as float.
 */
- (CGFloat) leftKerningForLayer:(GSLayer*) LeftLayer ;

//! Return the kerning value for the sequence self <> RightLayer.
/**
 This checks if there is class kerning or exception.
 @param RightLayer
 @return The kerning value as float.
 */
- (CGFloat) rightKerningForLayer:(GSLayer*) RightLayer ;

//! Sets the kerning for the sequence LeftLayer <> self.
/**
 This checks if there is class kerning or exception.
 @param Value
 @param LeftLayer
 */ 
- (void) setLeftKerning:(CGFloat) Value forLayer:(GSLayer*) LeftLayer;

//! Sets the kerning for the sequence self <> RightLayer.
/**
 This checks if there is class kerning or exception.
 @param Value
 @param RightLayer
 */ 
- (void) setRightKerning:(CGFloat) Value forLayer:(GSLayer*) RightLayer;

//! Returns a boolean value if LeftLayer <> self has a kerning exeption.
/**
 @param LeftLayer
 @return A BOOL
 */
- (BOOL) leftKerningExeptionForLayer:(GSLayer*) LeftLayer ;

/** Sets, if LeftLayer <> self has a exception or not.
 
 @param Exeption	if it is a exetion or not
 @param LeftLayer	The layer on the left
 */
- (void) setLeftKerningExeption: (BOOL) Exeption forLayer:(GSLayer*) LeftLayer ;

/** Returns a boolean value if self <> RightLayer has a kerning exeption.

 @param RightLayer
 @return A BOOL
 */
- (BOOL) rightKerningExeptionForLayer:(GSLayer*) RightLayer ;

/** Sets, if LeftLayer <> self has a exception or not.

 @param Exeption	if it is a exetion or not
 @param RightLayer	The layer to the right
 */
- (void) setRightKerningExeption: (BOOL) Exeption forLayer:(GSLayer*) RightLayer ;


/// Is called from element objects (anchors, components) if it has changed.
- (void) elementDidChange:(GSElement*) Element;


#pragma mark Selection
/** @name Selection */
/** adds a element to the selection.

 @param newSelection The element to add to the selection.
 */
- (void) addSelection:(GSElement*) newSelection ;
- (void) addObjectsFromArrayToSelection:(NSArray*) Objects ;
- (void) removeObjectFromSelectionAtIndex:(NSUInteger)theIndex ;
- (void) removeObjectFromSelection:(id)Object ;
- (void) removeObjectsFromSelection:(NSArray*)Objects ;
- (void) clearSelection ;
#pragma mark updates
- (void) setDisableUpdates;
- (void) setEnableUpdates;
/// Is called from an object after it changed the outline of the layer.
- (void) updatePath ;
/// marks the RSB and LSB to need update.
- (void) setNeedUpdateMetrics;
/// Recalculates the LSB and RSB using the mectrix keys.
- (void) syncMetrics;
/// Recalculates the LSB and RSB.
- (void) updateMetrics ;
- (CGFloat) sidebearingValue:(BOOL)Left forKey:(NSString*)Key ;
/** Metrics for the Layer

 This fetches the vertical metrics from the fonts fontMaster with the same layerId/assosiatedlayerId and the width from the layer.
 */
- (GSGlyphMetrics) glyphMetrics ;
/// The Bounding box of the path.
- (NSRect) bounds ;
- (void) cleanUpPaths ;
/// checks is all Nodes have the correct connection setting. 
- (void) checkConnections ;
- (void) correctPathDirection ;
- (void) roundSelectedCoordinates ;
- (void) roundCoordinates ;
/// add Extreme Points to all paths.
- (void) addExtremePoints;
/// The undoManager of the parent (Glyph)
- (NSUndoManager*) undoManager ;
/// Returns the containing Glyphs. it is a eqivalent to the parent property.
- (GSGlyph*) glyph;

/// Returns the element dicts of all selected elements
- (NSDictionary*) selectionDict ;

/** Returns the bezierpath encoded as NSData.

 This is necessary to send the bezierpath over the Distributed Objects Bridge.
 @return a bezierpath encoded as NSData.
 */
- (NSData*) bezierData ;

/** Transforms all selected elements.

 This applies the Transform to all elements in the selection.
 */
- (void) transformSelection:(NSAffineTransform*) Transform ;
- (void) transformSelection: (NSAffineTransform*) Transform checkForSelection:(BOOL) CheckForSelection ;
- (void) decomposeComponents ;
/// Decomposes the Component and adds the (scaled) paths.
- (void) decomposeComponent: (GSComponent*) Component;
/// Makes the component first.
- (void) makeFirstComponent: (GSComponent*) Component;
@end
