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

#import <GlyphsApp/GSFrameView.h>
#import <GlyphsCore/GSGeometryHelpers.h>
#import <GlyphsApp/GSEditViewController.h>

NS_ASSUME_NONNULL_BEGIN

typedef NS_ENUM(uint8_t, GSKerningMode) {
	GSKerningNothing = 0,
	GSKerningNormal = 1 << 0,
	GSKerningContextual = 1 << 1
};

@class GSLayer;
@class GSGlyph;
@class GSEditViewController;
@class GSTextStorage;
@class GSLayoutManager;
@class GSInspectorViewController;
@class GSInspectorView;

/// The view showing the edit area.
@interface GSGlyphEditView : NSView <NSMenuItemValidation>

@property (unsafe_unretained, nonatomic, nullable) NSResponder *delegate;
@property (unsafe_unretained, nonatomic, nullable) GSEditViewController *controller;
@property (strong, nonatomic, nullable) NSMutableDictionary<NSString *, NSNumber *> *axisLocation;
@property (nonatomic, unsafe_unretained) NSString *displayString;
@property (unsafe_unretained, nonatomic) NSString *stringValue;
@property (nonatomic) NSPoint drawOrigin;
@property (nonatomic, readonly) NSRect activeLayerRect;
@property (nonatomic, readonly) NSInteger maxWidth;
@property (assign) BOOL isDrawing;
@property (nonatomic, getter=isDrawingCheckerboard) BOOL drawCheckerboard;

- (NSUInteger)replaceOccurrencesOfString:(NSString *)target withString:(NSString *)replacement;

- (UTF32Char)charAtIndex:(NSUInteger)idx;

- (void)updateBoundsFromFrameView;

#ifndef GLYPHS_LITE
- (GSWritingDirection)checkVerticalWritingDirection:(GSWritingDirection)direction;
#endif

- (NSString *)displayString:(GSFormatVersion)format;

- (NSArray *)displayAttributedData:(GSFormatVersion)format;

- (void)checkAllGlyphs;

- (NSMenu *)defaultMenu;

- (void)redraw:(id)sender;

/// ----------------------------------------------------------------------------
/// @name Extracted from `GSTextStorage`
/// TODO: Sort properly
/// ----------------------------------------------------------------------------

// includes marked text
@property (unsafe_unretained, readonly, nonatomic) NSAttributedString *displayText;

@property (unsafe_unretained, nonatomic, readonly, nullable) id selectedLayerId;

- (IBAction)zoomFitInWindow:(id)sender;
/**
 Zooms to fit the given rect and scrolls it into the center of the frame.

 - Parameter rect: The target rect in font units.
 - Parameter padding: Padding in font units to be applied around the rect.
 */
- (void)zoomToRect:(NSRect)rect padding:(NSSize)padding;

- (NSRect)convertLayerRectToViewRect:(NSRect)rect;

- (NSRect)convertLayerRectToFrameRect:(NSRect)rect;

+ (void)displayString:(NSMutableString *)displayString fromChar:(UTF32Char)Char glyph:(nullable GSGlyph *)glyph lastHasSlash:(BOOL *)lastHasSlash ASCIIonly:(BOOL)Save;


/// The scale of the view.
@property (nonatomic) CGFloat scale;

/// The currently active cursor.
@property (nonatomic, strong, nullable) NSCursor *cursor;

/// The active glyphs layer.
/// Returns the selected layer if it is the only one selected, otherwise returns nil.
/// In the edit view, this is the layer that has a gray info box.
@property (nonatomic, strong, nullable) GSLayer *activeLayer;

/// The position of the activeLayer.
/// This is in scaled view coordinates.
/// @see scale
@property (nonatomic) NSPoint activePosition;

/// The index of the character of the active layer in the string.
@property (nonatomic) NSUInteger activeIndex;

/// The layer selection range after features have been applied.
///
/// When setting this property, the `selectedRange` property should also be set to the corresponding converted character range.
/// When setting the `selectedRange` property (except in the case above), this property should be set to {NSNotFound, 0}.
/// When getting this property, the actual ivar should only be returned if it is not {NSNotFound, 0}. Otherwise, the corresponding converted character range should be returned.
///
/// @note Setting this property should implicitly set `selectionAnchorLayerIndex` if its length is 0.
@property (nonatomic) NSRange selectedLayerRange;

/// Marks the starting point of the selection.
/// @note This property should be set implicitly when `selectedLayerRange` is set and its length is 0.
@property (nonatomic) NSUInteger selectionAnchorLayerIndex;

@property (nonatomic) NSPoint currentMousePosition;

- (void)insertLayersWithGlyphs:(NSArray<GSGlyph *> *)glyphs;

- (void)replaceActiveLayersWithGlyphs:(NSArray<GSGlyph *> *)glyphs;

/// Number of layers in the view.
/// This might be different than the number of characters in the string after the features are applied.
@property (nonatomic, readonly) NSUInteger cachedLayerCount;

/// Set if spacing is active.
@property (nonatomic) BOOL doSpacing;

/// Set if kerning is active.
@property (nonatomic) BOOL doKerning;

@property (nonatomic) GSKerningMode kerningMode;

@property (nonatomic) NSRect glyphFrame;
@property (nonatomic, readonly) NSRect userVisibleRect;
@property (nonatomic, readonly) NSRect safeVisibleRect;

@property (nonatomic, readonly, nullable) NSColor *canvasColor;
@property (nonatomic, readonly, nullable) NSColor *layerBackgroundColor;
@property (nonatomic, readonly, nullable) NSColor *backgroundStrokeColor;
@property (nonatomic, readonly, nullable) NSColor *backgroundStrokeColorDark;
@property (nonatomic, readonly, nullable) NSColor *otherLayersStrokeColor;
@property (nonatomic, readonly, nullable) NSColor *otherLayersStrokeColorDark;
@property (nonatomic, readonly, nullable) NSColor *foregroundFillColor;
@property (nonatomic, readonly, nullable) NSColor *foregroundStrokeColor;
/// Deprecated, use 'foregroundStrokeColor' instead.
@property (nonatomic, readonly, nullable) NSColor *foregroundColor;

@property (nonatomic) BOOL shouldDrawDark;

- (NSPoint)getLocation:(nullable NSEvent *)theEvent;

/// Translates the view coordinate from the event into glyph coordinates of the active layer.
/// @param theEvent A mouse down event
/// @return The coordinates
- (NSPoint)getActiveLocation:(nullable NSEvent *)theEvent;

/// Returns the cached layer at the given index.
/// @param idx The cached index
/// @return The layer
- (nullable GSLayer *)cachedGlyphAtIndex:(NSUInteger)idx;

/// Returns the cached position at a layer index.
/// @param idx The cached index
/// @return The position
- (NSPoint)cachedPositionAtIndex:(NSUInteger)idx;

/// Converts the given graphical position to a layer index.
/// @param point The graphical position to check, in view coordinates.
/// @return The index of the layer whose bounding box contains the point.
- (NSUInteger)layerIndexForPoint:(NSPoint)point;

/// Converts the given graphical position to a layer index, preferring a layer whose drawn outline contains the point.
///
/// - Parameter point: The graphical position to check, in view coordinates.
/// - Returns: The index of the layer whose outline contains the point, or whose bounding box contains it when no outline is hit.
- (NSUInteger)layerIndexForGlyphSelectionAtPoint:(NSPoint)point;

- (void)drawLayer:(nonnull GSLayer *)layer atPoint:(NSPoint)layerOrigin asActive:(BOOL)active attributes:(nullable NSDictionary *)attributes;

- (void)drawLayer:(nonnull GSLayer *)layer atPoint:(NSPoint)layerOrigin attributes:(nullable NSDictionary *)attributes filled:(BOOL)filled;

/// Draws the background image of the given glyph layer into the receiver’s background CA layer. The CA layer is created if necessary.
/// @param layer The glyph layer providing the background image. If this is nil, the current background image is removed.
/// @param layerOrigin The origin of the given glyph layer.
/// @param active If this is YES, the image is highlighted to indicate that it belongs to the selected glyph layer.
- (void)drawBackgroundImageOfLayer:(nullable GSLayer *)layer atPoint:(NSPoint)layerOrigin asActive:(BOOL)active;

- (void)hideBackgroundImageCALayer;

- (void)reflow;

- (NSAffineTransform *)zoomTransformForPosition:(NSPoint)position doOffset:(BOOL)offset;

- (void)bezierPathToViewSpace:(NSBezierPath *)bezierPath atPoint:(NSPoint)layerOrigin doOffset:(BOOL)offset;

- (void)bezierPathToViewSpace:(NSBezierPath *)bezierPath atPoint:(NSPoint)layerOrigin;

/// Attempts to add a background image from the pasteboard to the active glyph layer.
/// If the pasteboard contains file paths instead, attempts to import outlines from the referenced files.
- (BOOL)addBackgroundImageFromPasteboard:(nonnull NSPasteboard *)pasteboard;

- (void)replaceCharactersInRange:(NSRange)aRange withString:(nonnull NSString *)string;

- (void)insertCharacter:(UTF32Char)codePoint atLocation:(NSInteger)insertionLocation transitioningFromOrigin:(id)originElement;

/// Switches to the layer with the given layer id for the given range of characters as in the original string.
/// @param layerId The layer to switch to.
/// @param associatedMasterId If this argument is non-nil and the master id matches the id of the currently active master, the function will remove all layer id attributes from the text in the given range instead of setting new layer id attributes.
/// @param range The range in which to switch layers. The function switches no layers if the range extends past the text storage.
- (void)switchToLayerWithId:(NSString *)layerId associatedMasterId:(nullable NSString *)associatedMasterId inRange:(NSRange)range;


@end

NS_ASSUME_NONNULL_END
