//
//  GlyphsPathPlugin.h
//  GlyphsCore
//
//  Created by Georg Seifert on 26.04.09.
//  Copyright 2009 schriftgestaltung.de. All rights reserved.
//

#import <GlyphsCore/GSContainerProtocol.h>
#import <GlyphsApp/GSGlyphViewControllerProtocol.h>
#import <GlyphsCore/GSHint.h>
#import <GlyphsCore/GSSelectableElementProtocol.h>
#import <GlyphsApp/GSToolPlugin.h>
#import <GlyphsApp/GlyphsToolDrawProtocol.h>
#import <GlyphsApp/GlyphsToolEventProtocol.h>

@class GSPath;
@class GSLayer;
@class GSAnchor;
@class GSComponent;
@class GSSnapper;
@class GSGuide;
@class GSFontMaster;
@class GSColorLabelViewController;
@class GSHandle;

NS_ASSUME_NONNULL_BEGIN

extern NSColor *NodeSmoothColorDefault;
extern NSColor *NodeSmoothColorDefaultDark;
extern NSColor *NodeCornerColorDefault;
extern NSColor *NodeCornerColorDefaultDark;
extern NSColor *ComponentColor;
extern NSColor *ComponentColorLocked;
extern NSColor *ComponentColorAligned;
extern NSColor *ComponentColorHorizontalAligned;
extern NSColor *ComponentColorDark;
extern NSColor *ComponentColorLockedDark;
extern NSColor *ComponentColorAlignedDark;
extern NSColor *ComponentColorHorizontalAlignedDark;
extern NSColor *ZonesColorDefault;
extern NSColor *ZonesColorDefaultDark;
extern NSColor *LocalGuideColorDefault;
extern NSColor *LocalGuideColorDefaultDark;
extern NSColor *GlobalGuideColorDefault;
extern NSColor *GlobalGuideColorDefaultDark;
extern NSColor *NodeSmoothColor;
extern NSColor *NodeSmoothColorDark;
extern NSColor *NodeCornerColor;
extern NSColor *NodeCornerColorDark;
extern NSColor *HandleColor;
extern NSColor *MetricsColor;
extern NSColor *ZonesColor;
extern NSColor *LocalGuideColor;
extern NSColor *GlobalGuideColor;
extern NSColor *GridMainColor;
extern NSColor *GridSubColor;
extern NSColor *GridMainColorDefault;
extern NSColor *GridMainColorDefaultDark;
extern NSColor *GridSubColorDefault;
extern NSColor *GridSubColorDefaultDark;

@class GSAlignmentZone;

typedef void (^ApplyAllLayersPathHandler)(NSArray <NSIndexPath *>*indexPaths, NSMutableArray *nodes, GSLayer *layer);
typedef void (^ApplyAllLayersComponentHandler)(NSIndexSet *indexes, NSMutableArray *nodes, GSLayer *layer);

/**
 A base class for all path editing tools. It handles drawing and basic path interaction

 Subclass it for custom tool plugins
 */
#if !TARGET_OS_IOS
@interface GlyphsPathPlugin : GSToolPlugin <GlyphsToolDraw, GlyphsToolEvent, GSContainerProtocol, NSMenuDelegate, NSTextViewDelegate>
#else
@interface GlyphsPathPlugin : GSToolPlugin <GlyphsToolDraw, GlyphsToolEvent, GSContainerProtocol>
#endif
{
	// BOOL hasDragged;
	BOOL _dragging;
	NSPoint _dragStart;
	NSPoint _dragCurrent;
	NSPoint _dragElementOffset;
	NSPoint _contextClickPosition;
	// NSPoint _lastDragPosition;
	NSUInteger dragModifierFlag;
	// GSLayer *shadowLayer;
	NSMutableArray *_snappers;
	NSMutableArray<GSSnapper *> *_activeSnappers;
	NSImage *_toolBarIcon; // compatibility with older plugin
	GSLayer *_activeLayer;
	GSLayer *_foregroundLayer;
	GSFontMaster *_fontMaster;
	GSSelectableElement *_grabbedElement;
	GSSelectableElement *_highlightedElement;
	NSMutableDictionary *_pointsForTooltips;
	NSMutableArray<GSSelectableElement *> *_shiftedElements; // per Mouseover+Option key, nodes that are overlapping are moved apart to be able to select them individually
	NSMutableDictionary<NSValue *, NSNumber *> *_justAddedElements;
	NSRect _selectionBounds;
	NSAffineTransform *_selectionBoundsAngle;
	NSRect _shadowSelectionBounds;
	CGFloat _interfaceScale;
	BOOL _shouldAlias;
	GSColorLabelViewController *_colorButtonsViewController;
	BOOL _isCancel;
	GSElement *_activeElement;

	NSTimer *_removeSnapperTimer;
	BOOL _shouldDrawDark;
}

/** Yes if in a dragging state */
@property (nonatomic) BOOL dragging;

@property (readonly) BOOL showNodes;

@property (nonatomic, readonly) BOOL showGuides;

/** Origin of the current dragging operation
 */
@property (nonatomic) NSPoint dragStart;

/** The scaling factor for interface elements.

 On Retina displays its 1.75, otherwise 1.0
 */
@property (nonatomic, readonly) CGFloat interfaceScale;

@property (nonatomic, strong, nullable) NSArray<GSHandle *> *extraHandles;

@property (nonatomic, nullable, strong) GSSelectableElement *highlightedElement;

- (void)updateHighlightedElement:(GSLayer *)layer event:(NSEvent *)event;

- (void)updateHighlightedElement:(GSLayer *)layer position:(NSPoint)pos;

@property (nonatomic, strong) NSDictionary<NSValue *, NSNumber *> *justAddedElements;

- (void)justAddedElement:(GSSelectableElement *)newElement;

- (void)justAddedElementsFromArray:(NSArray *)newElements;

/** Is called when the return key is pressed.

 Overwrite for your own behavior.
 @warning Never call that yourself.
 @param sender Typically the object that invoked this method.
 */
- (void)insertNewline:(nullable id)sender;

- (NSPoint)finalPointForNode:(GSSelectableElement *)node;

/** Draws the starting node of an open path

 @param node  the start or end node
 @param sel   If the node is selected or not
 @param layerOrigin The origin point of the current layer
 */
- (void)drawBegin:(GSNode *)node isSelected:(BOOL)sel atPoint:(NSPoint)layerOrigin;

- (void)activeCornerIndexes:(const NSRect *)bounds corners:(GSAlignment *)corners count:(int *)count;

- (void)drawHandlesForBounds:(NSRect)bounds atPoint:(NSPoint)layerOrigin angle:(nullable NSAffineTransform *)transform;

- (void)drawHandle:(NSPoint)point isSelected:(BOOL)selected atPoint:(NSPoint)layerOrigin;
/**
 Draws a node

 @param path     The path that contains the node
 @param idx      The index of the node
 @param selected If the node is selected or not
 @param layerOrigin    The origin point of the current layer
 */
- (void)drawHandle:(GSPath *)path atIndex:(NSUInteger)idx isSelected:(BOOL)selected atPoint:(NSPoint)layerOrigin simple:(BOOL)simple;

/** Returns the radius of a knob.

 @param isSelected Whether to return the size of a selected knob.
 */
- (CGFloat)knobSizeIsSelected:(BOOL)isSelected;

- (void)drawKnob:(NSPoint)point type:(GSNodeType)type selected:(BOOL)selected atPoint:(NSPoint)layerOrigin;

/** The rect that for drawing the node

 @param point		the node position
 @param selected	If the node is selected or not
 @param layerOrigin		The origin point of the current layer

 @return the rect
 */
- (NSRect)getHandleRect:(NSPoint)point isSelected:(bool)selected atPoint:(NSPoint)layerOrigin;

- (NSRect)getHandleRect:(NSPoint)pt isSelected:(bool)selected type:(GSNodeType)type atPoint:(NSPoint)layerOrigin;

- (NSRect)getHandleRect:(NSPoint)point isSelected:(bool)selected size:(CGFloat)sizeScale atPoint:(NSPoint)layerOrigin;

- (void)drawGuide:(GSGuide *)guide atPoint:(NSPoint)layerOrigin selected:(BOOL)selected global:(BOOL)global;

- (void)drawHint:(GSHint *)hint atPoint:(NSPoint)layerOrigin selected:(BOOL)selected;

- (void)drawShadowAccents:(GSLayer *)layer atPoint:(NSPoint)layerOrigin fullCloud:(BOOL)fullCloud;

@property (nonatomic) NSPoint transformOrigin;

- (NSRect)rectForHandle:(GSAlignment)handleIndex forBounds:(NSRect)bounds angle:(nullable NSAffineTransform *)transform handleSize:(CGFloat)handleSize scale:(CGFloat)scale;
#ifndef GLYPHS_VIEWER

- (NSPoint)snapAtPoint:(NSPoint)point withModifier:(NSEventModifierFlags)modifierFlag;

- (void)addSnapper:(GSSnapper *)snapper;

- (void)addSnapperWithPoint:(NSPoint)point;

- (void)addActiveSnapper:(GSSnapper *)snapper;

- (void)cleanSnappers:(id)sender;

#ifndef GLYPHS_LITE
- (nullable NSArray *)smartAnchorsForComponent:(GSComponent *)component;
#endif

- (NSOrderedSet *)selectedObjects;

- (IBAction)selectAll:(nullable id)sender;

- (IBAction)deselectAll:(nullable id)sender;

- (NSMutableArray *)indexPaths:(GSLayer *)layer doBackground:(BOOL *)doBackground layerGroup:(NSArray *_Nonnull *_Nonnull)layerGroup doAllMasters:(BOOL)doAllMasters checkCompatibility:(BOOL)checkCompatibility;

#ifndef GLYPHS_LITE

- (void)autohintLayers:(NSArray *)layers;

#endif

- (void)delSelection;

- (void)delSelectionWithModifier:(NSEventModifierFlags)modifierFlag;

- (IBAction)selectionToBackground:(id)sender;

#ifndef GLYPHS_LITE
- (IBAction)selectionToBackgroundForAll:(id)sender;
#endif

- (IBAction)selectionToBackgroundKeepOldBackground:(id)sender;

- (IBAction)componentFromSelection:(id)sender;

- (IBAction)swapForegroundWithBackground:(id)sender;

- (nullable GSNode *)connectPathsWithNode:(GSNode *)moveNode andNode:(GSNode *)overNode;

- (nullable GSNode *)nodeAtPoint:(NSPoint)loc atLayer:(GSLayer *)layer excludeNode:(nullable GSNode *)exclude ignoreLocked:(BOOL)ignoreLocked;

- (nullable GSNode *)nodeAtPoint:(NSPoint)loc atLayer:(nullable GSLayer *)layer excludeNodes:(nullable NSSet *)excludes traverseComponents:(BOOL)traverseComponents ignoreLocked:(BOOL)ignoreLocked;

- (void)transformSelection:(NSAffineTransform *)transform;

- (void)transformSelectionInLayer:(GSLayer *)layer shadowLayer:(GSLayer *)shadowLayer transform:(NSAffineTransform *)transform;

- (void)moveSelectionLayer:(GSLayer *)layer shadowLayer:(GSLayer *)shadowLayer withPoint:(NSPoint)point withModifier:(NSEventModifierFlags)modifierFlag;

- (void)moveSelectionWithPoint:(NSPoint)point withModifier:(NSEventModifierFlags)modifierFlag;

- (BOOL)setHintDraggingKnob:(GSLayer *)layer withPoint:(NSPoint)point;

- (void)drawMetricsForLayer:(GSLayer *)layer atPoint:(NSPoint)layerOrigin asActive:(BOOL)active;

- (void)editAnchorName:(GSAnchor *)anchor;

- (void)setInterpolate:(GSLayer *)layer withPoint:(NSPoint)offset;

- (nullable NSString *)selectionEPSDataFromDict:(NSDictionary *)selectedObjects;

- (IBAction)addComponent:(id)sender;

- (IBAction)addAnchor:(id)sender;

#ifndef GLYPHS_LITE
- (IBAction)autohint:(id)sender;

- (IBAction)dehint:(id)sender;
#endif

- (IBAction)addVHint:(id)sender;

- (IBAction)addHHint:(id)sender;

- (nullable NSArray *)addHintsForNodes:(NSMutableArray *)nodes toLayer:(GSLayer *)layer vertical:(BOOL)vertical type:(GSHintType)type position:(NSPoint)position;

- (NSSet *)touchedByHintsIndexes:(GSLayer *)layer;

- (IBAction)addGuide:(id)sender;

- (IBAction)reversePaths:(id)sender;

- (IBAction)checkConnections:(id)sender;

- (IBAction)addExtremes:(id)sender;

- (IBAction)addExtremesForce:(id)sender;

- (IBAction)alignPoints:(id)sender;

- (IBAction)clear:(NSMenuItem *)sender;

- (IBAction)clearForAll:(NSMenuItem *)sender;

#endif
#ifndef GLYPHS_LITE
@property (assign) int findSubpathIndex;
@property (assign) int findSubpathCount;
- (void)setFindPathsPasteboard:(GSPath *)path;
#endif
+ (BOOL)pasteOutlines:(NSData *)data intoLayer:(GSLayer *)layer format:(GSFormatVersion)format checkSelection:(BOOL)checkSelection error:(NSError **)error;
#ifndef GLYPHS_LITE
- (IBAction)makeNodeFirstForAll:(id)sender;
- (IBAction)makeNodeFirst:(id)sender;
- (IBAction)focusOnSelectedPaths:(id)sender;
- (IBAction)clearFocusOnPaths:(id)sender;
#endif

#if TARGET_OS_IOS
- (void)addComponents:(NSArray *)result toLayer:(GSLayer *)layer;

- (void)delSelectionWithModifier:(NSEventModifierFlags)modifierFlag;
#endif

- (GSLayer *)activeLayer:(nullable id)sender;

- (void)applyToPathsInAllLayers:(BOOL)forAll sender:(nullable NSMenuItem *)sender process:(ApplyAllLayersPathHandler)block;

- (void)applyToComponentInAllLayers:(BOOL)forAll sender:(nullable NSMenuItem *)sender process:(ApplyAllLayersComponentHandler)block;

@end

NS_ASSUME_NONNULL_END
