//
//  MPFunctionLayout.h
//  MathKit
//
//  Created by Kim Wittenburg on 07.08.14.
//  Copyright (c) 2014 Kim Wittenburg. All rights reserved.
//

#import "MPLayout.h"


/*!
 @header
 This file contains the <code>MPFunctionLayout</code> class.
 
 The <code>MPFunctionLayout</code> class is an abstract class that implements
 many of the methods from the layout system. Concrete subclasses implement the
 actual layout of a specific function and its children. For that reason
 <code>MPFunctionLayout</code> features a private cache. In that cache any
 subclass can store objects so they do not need to be recreated everytime the
 function is rendered.
 */



@class MPFunctionLayout, MPFunction, MPExpressionLayout;


/*!
    @class      MPFunctionLayout
    @abstract   A function layout represents a <code>@link
                //apple_ref/occ/cl/MPFunction@/link</code>.
 
    @discussion <code>MPFunctionLayout</code> is an abstract class that
                implements many required methods of the layout system. For more
                information about the layout system see the documentation on the
                <code>@link //apple_ref/occ/cl/MPLayout@/link</code> class.
 */
@interface MPFunctionLayout : MPLayout

/*!
    @method     functionLayoutForFunction:parent:
    @abstract   Creates a function layout that can draw the specified function.
 
    @discussion This method is the preferred whay to construct function layouts.
 
    @param      function
                The function to create a layout for. Must not be
                <code>nil</code>.
 
    @param      parent
                The parent of the created function layout. May be
                <code>nil</code>.
 
    @return     A newly created function layout.
 */
+ (MPFunctionLayout *)functionLayoutForFunction:(MPFunction *)function
                                         parent:(MPExpressionLayout *)parent;


/*!
    @method     initWithFunction:parent:
    @abstract   Initializes the receiver with the specified function and parent.
 
    @discussion This method should not be called direcly. It is however possible
                do perform custom initialization in sublcasses by overriding this method.
 
                This method is the designated initializer of the
                <code>MPFunctionLayout</code> class.

    @param      function
                The function represented by the receiver. Must not be
                <code>nil</code>.
 
    @param      parent
                The parent of the receiver or <code>nil</code> if it does not
                have one.
 
    @return     A newly initialized <code>MPFunctionLayout</code> instance.
 */
- (instancetype)initWithFunction:(MPFunction *)function
                          parent:(MPExpressionLayout *)parent;


/*!
    @property   function
    @abstract   The function represented by the receiver.
 */
@property (readonly, nonatomic, weak) MPFunction *function;


/*!
    @method     lineForPrivateCacheIndex:generator:
    @abstract   Returns the cached line for the specified private index.
 
    @discussion This is a convenience method that calls <code>@link
                //apple_ref/occ/instm/MPFunctionLayout/objectForPrivateCacheIndex:generator:@/link</code>.
                See the documentation on that method for details.
 
    @param      index
                The index of the line to retrieve. Private cache indexes start at <code>0</code>.
 
    @param      generator
                A block that generates a line in case there is no cached one.
 
    @return     The cached line or the newly generated one if there was no cache value.
 */
- (CTLineRef)lineForPrivateCacheIndex:(NSUInteger)index
                            generator:(CTLineRef (^)())generator;


/*!
    @method     objectForPrivateCacheIndex:generator:
    @abstract   Returns the cached value for the specified private index.
 
    @discussion If there is no object in the private cache for the specified
                index the specified <code>generator</code> is invoked. The result
                of the <code>generator</code> is then stored at the specified
                <code>index</code> and returned.
 
    @param      index
                The index of the private cache item to retrieve. Private cache
                indexes start at <code>0</code>.

    @param      generator
                A block that generates an object in case there is no cached one.
 
    @return     The cached object or the newly generated one if there was no
                cache value.
 */
- (id)objectForPrivateCacheIndex:(NSUInteger)index
                       generator:(id (^)())generator;

@end



/*!
    @category   MPFunctionLayout (MPSubclassOverride)
    @abstract   The methods defined in this category must be implemented by any
                concrete subclass of <code>MPFunctionLayout</code>.
 */
@interface MPFunctionLayout (MPSubclassOverride)

/* Apart from the methods below it is recommended (although not required) to
 * implement a method in the following form:
 * - (CustomFunctionType *)customFunction
 * {
 *     return (CustomFunctionType *)self.function;
 * }
 */


/*!
    @method     childAtIndexUsesSmallSize:
    @abstract   Determines whether the child expression at the specified index
                should be drawn using the small font.
 
    @discussion This method may be overridden to change the default behaviour.
 
    @param      index
                The index of the child whose size is to be determined.

    @return     <code>YES</code> if the receiver's child at the specified
                <code>index</code> should use the small font, <code>NO</code>
                otherwise. The default implementation returns <code>NO</code>.
 */
- (BOOL)childAtIndexUsesSmallSize:(NSUInteger)index; // May be implemented


/*!
    @method     offsetOfChildLayoutAtIndex:
    @abstract   Implementation requirement from superclass. See <code>@link
                //apple_ref/occ/instm/MPLayout(MPSubclassImplement)/offsetOfChildLayoutAtIndex:@/link</code>
                for details.
 */
- (NSPoint)offsetOfChildLayoutAtIndex:(NSUInteger)index;


/*!
    @method     indexPathForLocalMousePoint:
    @abstract   Performs hit testing.
 
    @discussion This method is called when the user selected a point in a
                function that is not in any of its children. The return value of
                this method identifies the position relative to the function
                represented by the receiver where the caret is to be placed.
 
                This method must be implemented by subclasses.
 
    @param      point
                The location the user clicked at relative to the receiver.
 
    @return     An index path identifying the new caret position relative to the
                function represented by the receiver. Use an index path
                containing a single index to place the caret before or after the
                represented function (<code>0</code> means before, <code>1</code>
                means after).
 */
- (NSIndexPath *)indexPathForLocalMousePoint:(NSPoint)point;


/*!
    @method     generateBounds
    @abstract   Implementation requirement from superclass. See <code>@link
                //apple_ref/occ/instm/MPLayout(MPSubclassImplement)/generateBounds@/link</code>
                for details.
 */
- (NSRect)generateBounds;


/*!
    @method     draw
    @abstract   Implementation requirement from superclass. See <code>@link
                //apple_ref/occ/instm/MPLayout(MPSubclassImplement)/draw@/link</code>
                for details.
 */
- (void)draw;


/*!
    @method     indexOfLeadingChild
    @abstract   Identifies the index of the receiver's child that will get
                selected when the cursor <i>enters</i> the function in the
                direction of reading.
 
    @discussion You may implement this method do override the default behaviour.
 
    @return     The index of the leading child. The default implementation
                returns <code>0</code>.
 */
- (NSUInteger)indexOfLeadingChild;


/*!
    @method     indexOfTrailingChild
    @abstract   Identifies the index of the receiver's child that will get
                selected when the cursor <i>enters</i> the function in the
                direction opposite to reading.
 
    @discussion You may implement this method do override the default behaviour.
 
    @return     The index of the trailing child. The default implementation
                returns <code>0</code>.
 */
- (NSUInteger)indexOfTrailingChild;


/*!
    @method     indexOfChildBeforeChildAtIndex:
    @abstract   Identifies the index of the receiver's child that will get
                selected when the cursor <i>leaves</i> the child at the specified
                index in the direction opposite to reading.
 
    @discussion Return <code>NSNotFound</code> from this method if the function
                should be <i>left</i> when the child at the specified index is
                <i>left</i>.
 
                You may implement this method to override the default behaviour.
 
    @param      index
                The index of the child the caret <i>left</i>.
 
    @return     The index of the child that is to be <i>entered</i> or
                <code>NSNotFound</code> if there are no more children. The
                default implementation returns <code>NSNotFound</code>.
 */
- (NSUInteger)indexOfChildBeforeChildAtIndex:(NSUInteger)index;


/*!
    @method     indexOfChildAfterChildAtIndex:
    @abstract   Identifies the index of the receiver's child that will get
                selected when the cursor <i>leaves</i> the child at the specified
                index in the direction of reading.
 
    @discussion Return <code>NSNotFound</code> from this method if the function
                should be <i>left</i> when the child at the specified index is
                <i>left</i>.
 
                You may implement this method to override the default behaviour.
 
    @param      index
                The index of the child the caret <i>left</i>.
 
    @return     The index of the child that is to be <i>entered</i> or
                <code>NSNotFound</code> if there are no more children.
 */
- (NSUInteger)indexOfChildAfterChildAtIndex:(NSUInteger)index;


/*!
    @method     indexOfChildBelowChildAtIndex:
    @abstract   Returns the index of the child that is graphically positioned
                below the child at the specified index.
 
    @discussion If there are no other children below the one at the specified
                index this method should return <code>index</code>.
 
                You may implement this method to override the default behaviour.
 
    @param      index
                The index of the child whose neighbor is to be determined.
 
    @return     The index of the child directly below the one at the specified
                index. The default implementation returns <code>index</code>.
 */
- (NSUInteger)indexOfChildBelowChildAtIndex:(NSUInteger)index;


/*!
    @method     indexOfChildAboveChildAtIndex:
    @abstract   Returns the index of the child that is graphically positioned
                above the child at the specified index.
 
    @discussion If there are no other children above the one at the specified
                index this method should return <code>index</code>.
 
                You may implement this method to override the default behaviour.
 
    @param      index
                The index of the child whose neighbor is to be determined.
 
    @return     The index of the child directly above the one at the specified
                index. The default implementation returns <code>index</code>.
 */
- (NSUInteger)indexOfChildAboveChildAtIndex:(NSUInteger)index;


/*!
    @method     indexesOfRemainingChildren
    @abstract   Returns the indexes of the receiver's children that should
                replace the receiver if it is deleted.
 
    @discussion You may implement this method to override the default behaviour.
 
    @return     The indexes of the children that replace the receiver when it is
                deleted. The default implementation returns an empty index set.
 */
- (NSIndexSet *)indexesOfRemainingChildren;

@end