//
//  GSHobbySplines.h
//  StrokeTool
//
//  Created by Georg Seifert on 31/10/2016.
//  Copyright © 2016 Georg Seifert. All rights reserved.
//

#ifndef GSHobbySplines_h
#define GSHobbySplines_h

#import <GlyphsCore/GSBase.h>

@class GSPath;
@class GSNode;
@class GSHobbyNodeInfo;

NS_ASSUME_NONNULL_BEGIN

/// Key for the temp data on `GSNode` that is written to the original node when converting a path to a standard Bézier path. The value is a `GSHobbyKnot`.
static NSString * const GSHobbyKnotTempDataKey = @"GSHobbyKnot";
/// `x` and `y` coordinate of a Hobby node control point if the Hobby curve does not continue on the side of that control point.
static const CGFloat GSHobbyTerminalCoordinate = CGFLOAT_MIN;

typedef NS_ENUM(uint8_t, GSHobbyType) {
	/// `leadingType` at path beginning and `trailingType` at path end.
	GSHobbyTypeEndpoint = 0,
	/// `leadingType` or `trailingType` when control points are known.
	GSHobbyTypeExplicit = 1,
	/// `leadingType` or `trailingType` when a direction is given.
	GSHobbyTypeGiven = 2,
	/// `leadingType` or `trailingType` when a curl is desired.
	GSHobbyTypeCurl = 3,
	/// `leadingType` or `trailingType` when the METAPOST algorithm should choose the direction.
	GSHobbyTypeOpen = 4,
	/// `leadingType` when cycling back to the first point.
	GSHobbyTypeEndCycle = 5,
};

@interface GSHobbyKnot : NSObject {
	NSPoint _position;
	GSHobbyType _leadingType;
	GSHobbyType _trailingType;
@public
	NSPoint _leadingControlPoint;
	NSPoint _trailingControlPoint;
	GSNodeConnection _connection;
}
@property (nonatomic, readonly) NSPoint position;
@property (assign) GSHobbyType leadingType;
@property (assign) GSHobbyType trailingType;
/// Its coordinates are `GSHobbyTerminalCoordinate` if the point does not exist because the knot is placed at the beginning of an open Hobby curve section.
@property (assign) NSPoint leadingControlPoint;
/// Its coordinates are `GSHobbyTerminalCoordinate` if the point does not exist because the knot is placed at the end of an open Hobby curve section.
@property (assign) NSPoint trailingControlPoint;
@property (assign) GSNodeConnection connection;
@property (nonatomic) CGFloat leadingCurl;
@property (nonatomic) CGFloat trailingCurl;
@property (nonatomic) CGFloat leadingTension;
@property (nonatomic) CGFloat trailingTension;
@property (strong, nullable) GSHobbyKnot *previousKnot;
@property (strong, nullable) GSHobbyKnot *nextKnot;

+ (NSArray<GSHobbyKnot *> *)knotsForNodes:(NSArray<GSNode *> *)nodes
								fromIndex:(NSInteger)nodesStartIndex
								  toIndex:(NSInteger)nodesEndIndex
						  isClosedSection:(BOOL)closedSection
							 isClosedPath:(BOOL)closedPath;

+ (void)drawKnots:(NSArray<GSHobbyKnot *> *)knots isClosedSection:(BOOL)isClosedSection inPath:(GSPath *)path;

- (NSPoint)leadingHandlePositionForInfo:(GSHobbyNodeInfo *)info minDistance:(CGFloat)minDistance scale:(CGFloat)scale;
- (NSPoint)trailingHandlePositionForInfo:(GSHobbyNodeInfo *)info minDistance:(CGFloat)minDistance scale:(CGFloat)scale;

@end

NS_ASSUME_NONNULL_END

#endif /* GSHobbySplines_h */
