//
//  MPSumFunctionLayout.m
//  MathKit
//
//  Created by Kim Wittenburg on 23.04.14.
//  Copyright (c) 2014 Kim Wittenburg. All rights reserved.
//

#import "MPSumFunctionLayout.h"

#import "MPSumFunction.h"
#import "NSIndexPath+MPAdditions.h"


#define kSumFunctionStartExpressionOffset 0
#define kSumFunctionTargetExpressionOffset 0
#define kSumFunctionSumExpressionOffset 3
#define kSumFunctionTrailingOffset 5



@implementation MPSumFunctionLayout

- (MPSumFunction *)sumFunction
{
    return (MPSumFunction *)self.function;
}


- (NSUInteger)indexOfLeadingChild
{
    return 2;
}


- (NSUInteger)indexOfTrailingChild
{
    return 2;
}


- (NSUInteger)indexOfChildAfterChildAtIndex:(NSUInteger)index
{
    if (index != 2) {
        return 2;
    }
    return [super indexOfChildAfterChildAtIndex:index];
}


- (NSUInteger)indexOfChildBelowChildAtIndex:(NSUInteger)index
{
    return 0;
}


- (NSUInteger)indexOfChildAboveChildAtIndex:(NSUInteger)index
{
    return 1;
}


- (NSIndexSet *)indexesOfRemainingChildren
{
    return [NSIndexSet indexSetWithIndex:2];
}


- (CTLineRef)line
{
    CTLineRef line = [self lineForPrivateCacheIndex:0 generator:^CTLineRef{
        return [self createLineForString:@"∑"
                               usingFont:[NSFont fontWithName:@"Times New Roman"
                                                         size:self.contextInferredFontSize]];
    }];
    return line;
}


- (NSRect)localLineBounds
{
    NSRect lineBounds = CTLineGetBoundsWithOptions(self.line, 0);
    NSRect startExpressionBounds = [self childLayoutAtIndex:0].bounds;
    NSRect targetExpressionBounds = [self childLayoutAtIndex:1].bounds;
    CGFloat width = MAX(MAX(startExpressionBounds.size.width, targetExpressionBounds.size.width), lineBounds.size.width);
    CGFloat xPosition = (width - lineBounds.size.width) / 2;
    return NSMakeRect(xPosition, lineBounds.origin.y, lineBounds.size.width, lineBounds.size.height);
}


- (NSPoint)offsetOfChildLayoutAtIndex:(NSUInteger)index
{
    NSRect childBounds = [self childLayoutAtIndex:index].bounds;
    NSRect localLineBounds = [self localLineBounds];
    NSPoint offset;
    if (index == 0) {
        // Start Expression
        offset.x = localLineBounds.origin.x + localLineBounds.size.width / 2 - childBounds.size.width / 2;
        offset.y = localLineBounds.origin.y - kSumFunctionStartExpressionOffset - childBounds.size.height - childBounds.origin.y;
    } else if (index == 1) {
        // Target Expression
        offset.x = localLineBounds.origin.x + localLineBounds.size.width / 2 - childBounds.size.width / 2;
        offset.y = kSumFunctionTargetExpressionOffset + localLineBounds.size.height + localLineBounds.origin.y - childBounds.origin.y;
    } else {
        // Sum Expression
        MPLayout *startExpressionLayout = [self childLayoutAtIndex:0];
        MPLayout *targetExpressionLayout = [self childLayoutAtIndex:1];
        CGFloat sumWidth = MAX(MAX(localLineBounds.origin.x + localLineBounds.size.width, startExpressionLayout.bounds.size.width), targetExpressionLayout.bounds.size.width);
        offset.x = sumWidth + kSumFunctionSumExpressionOffset;
        offset.y = 0;
    }
    return offset;
}


- (BOOL)childAtIndexUsesSmallSize:(NSUInteger)index
{
    return (index == 0 || index == 1) ? YES : self.usesSmallSize;
}


- (NSIndexPath *)indexPathForLocalMousePoint:(NSPoint)point
{
    if (point.x < CTLineGetBoundsWithOptions(self.line, 0).size.width / 2) {
        return [NSIndexPath indexPathWithIndex:0];
    } else {
        return [NSIndexPath indexPathWithIndex:1];
    }
}


- (NSRect)generateBounds
{
    NSRect lineBounds = CTLineGetBoundsWithOptions(self.line, 0);
    NSRect startExpressionBounds = [self childLayoutAtIndex:0].bounds;
    NSRect targetExpressionBounds = [self childLayoutAtIndex:1].bounds;
    NSRect sumExpressionBounds = [self childLayoutAtIndex:2].bounds;
    NSRect bounds = lineBounds;
    
    bounds.size.width = MAX(lineBounds.size.width, startExpressionBounds.size.width);
    bounds.size.height += startExpressionBounds.size.height + kSumFunctionStartExpressionOffset;
    bounds.origin.y -= startExpressionBounds.size.height + kSumFunctionStartExpressionOffset;

    bounds.size.width = MAX(bounds.size.width, targetExpressionBounds.size.width);
    bounds.size.height += targetExpressionBounds.size.height + kSumFunctionTargetExpressionOffset;
    
    bounds.size.width += kSumFunctionSumExpressionOffset + sumExpressionBounds.size.width + kSumFunctionTrailingOffset;
    CGFloat yOffsetBottom = bounds.origin.y - sumExpressionBounds.origin.y;
    CGFloat yOffsetTop = sumExpressionBounds.size.height - (yOffsetBottom + bounds.size.height);
    bounds.size.height = MAX(yOffsetBottom, 0) + bounds.size.height + MAX(yOffsetTop, 0);
    bounds.origin.y = MIN(sumExpressionBounds.origin.y, bounds.origin.y);
    
    return bounds;
}


- (void)draw
{
    // Get the current context
    CGContextRef context = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
        
    // Set the text matrix
    CGContextSetTextMatrix(context, CGAffineTransformIdentity);
    
    // Draw the sum symbol
    CTLineRef line = [self line];
    CFRetain(line);
    NSRect localLineBounds = [self localLineBounds];
    CGContextSetTextPosition(context, localLineBounds.origin.x, 0);
    CTLineDraw(line, context);
        
    CFRelease(line);
}

@end
