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

#import <Cocoa/Cocoa.h>
#import <GlyphsCore/GSTransformableElement.h>

NS_ASSUME_NONNULL_BEGIN

@class GSGlyph;
@class GSFont;
@class GSLayer;

#ifndef GLYPHS_LITE
@class GSPartProperty;
#endif

#ifndef GLYPHS_VIEWER
@class GSNotifyingDictionary;
#else
#define GSNotifyingDictionary NSMutableDictionary
#endif
/// This class defines the component object. It is a subclass of GSElement

@interface GSComponent : GSTransformableElement {
	GSGlyph *_component;
	GSComponentAlignment _isAligned;
	GSLayer *_cachedLayer;
	NSDate *_lastChange;
  @public
	NSString *_componentName;
	NSString *_componentMasterId;
	NSString *_anchorTo;
	GSComponentAlignment _alignment;

#pragma GSAutoCodeStart ivars

	CGFloat _keepWeight;
	NSString *_anchor;

#pragma GSAutoCodeEnd ivars
}

- (BOOL)isEqualToComponent:(GSComponent *)other;

/** components are referenced by the glyph name.

If you set the componentName the component value is set and this is used during runtime. So you can change the glyph name of the base glyph during runtime.
*/
@property (strong, nonatomic, nullable) NSString *componentName;

@property (strong, nonatomic, nullable) NSString *componentMasterId;
@property (strong, nonatomic, nullable) NSString *componentLayerKey;
/** The base glyph

This is readonly. To set the base glyph use componentName: newBaseGlyph.name.
@see componentName
*/
@property (unsafe_unretained, readonly, nullable) GSGlyph *component;

@property (copy, nonatomic) NSString *anchorTo;

@property (nonatomic) GSComponentAlignment isAligned;

// Compatibility
@property (nonatomic, readonly) BOOL disableAlignment;

@property (nonatomic, readonly) BOOL doesAlign;
@property (nonatomic, readonly) BOOL shouldAlign;
@property (nonatomic, readonly) BOOL doesAttach;
@property (nonatomic, readonly) BOOL shouldAttach;

@property (nonatomic, readonly) GSComponentAlignment alignmentType;
#ifndef GLYPHS_LITE
/** The instance settings do Smart Components.

 It is a dictionary containing the parameter names as keys and the interpolation position as value.

	{
		Height = 70;
		Width = 70;
	}

 @see GSGlyph.partsSettings
 */
@property (strong, nonatomic, nullable) GSNotifyingDictionary *pieceSettings;

- (void)setPieceSettingsFast:(GSNotifyingDictionary *)pieceSettings;

- (void)setPieceValue:(CGFloat)value forKey:(NSString *)key;

- (CGFloat)pieceValueForKey:(NSString *)key;

#ifndef GLYPHS_VIEWER
- (nullable NSString *)hangulModelGlyph;

- (BOOL)isHangulKeyComponent;

- (void)convertPieceSettingsToID;
#endif
#endif
/** The bounds of the components

 @return the bounds
 */
- (NSRect)bounds;

/// The bezierPath of the component. It is already transformed.
- (nullable NSBezierPath *)bezierPath;

- (nullable NSBezierPath *)bezierPathIgnorePlaceholder:(BOOL)ignorePlaceholder;

- (nullable NSBezierPath *)bezierPathIgnorePlaceholder:(BOOL)ignorePlaceholder seen:(NSMutableSet *)seenComponents hasPaths:(BOOL *)hasPaths;

/// The bezierPath of open paths of the component. It is already transformed.
- (nullable NSBezierPath *)openBezierPath;

- (nullable NSBezierPath *)openBezierPath:(NSMutableSet *)seenComponents;

#ifndef GLYPHS_VIEWER
- (NSTimeInterval)lastOperation:(NSMutableSet *)seenComponents;
#endif

- (void)updateComponentGlyph;

- (void)updateComponentGlyphDontNotify;
- (void)updateComponentGlyphFast;
/** The Layer that the component is linked to.

 The is usually just the layer from the components glyph but might be the computed result of a smart component.

 @return the Layer that represents the component.
 */
- (nullable GSLayer *)componentLayer;

#ifndef GLYPHS_VIEWER

/** Decomposes the component to the containing Layer

It need to parent property set correctly. It calls `[_parent decomposeComponent:self]`.
*/
- (void)decompose;

#ifndef GLYPHS_LITE

/** If the component overlaps with the OtherComponent

 @param otherComponent The OtherComponent to test overlap.

 @return Returns YES if both components do overlap, otherwise NO.
 */
- (BOOL)intersects:(GSComponent *)otherComponent;

- (BOOL)intersectsDontCheckBounds:(GSComponent *)otherComponent;

- (nullable NSArray<NSValue *> *)intersectionsWithLineFrom:(NSPoint)startPoint to:(NSPoint)endPoint;

#endif

/** It makes the component the first in the containing Layer

It need to parent property set correctly. It calls `[_parent makeFirstComponent:self]`.
*/
- (void)makeFirst;

- (void)makeDisableAlignment;

- (void)makeEnableAlignment;

- (void)makeForceAlignment;
#endif
#ifndef GLYPHS_LITE
- (CGFloat)valueForAxis:(GSPartProperty *)axis;
#endif
#ifndef GLYPHS_VIEWER
- (void)preloadCachedLayers;
#endif

#pragma GSAutoCodeStart methods

/// The alignment.
@property (nonatomic) GSComponentAlignment alignment;

/// The keepWeight.
@property (nonatomic) CGFloat keepWeight;

/**
 If more than one anchor/_anchor pair would match, this property can be used to set the anchor to use for automatic alignment

 This can be set from the anchor button in the component info box in the UI
 */
@property (nonatomic, strong, nullable) NSString *anchor;

#pragma GSAutoCodeEnd methods

#ifndef GLYPHS_VIEWER
- (void)setAlignmentFast:(GSComponentAlignment)flag;
#endif

@end
NS_ASSUME_NONNULL_END
