//
//  MPSumFunctionLayout.m
//  MathPad
//
//  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 3
#define kSumFunctionTargetExpressionOffset 0
#define kSumFunctionSumExpressionOffset 3
#define kSumFunctionTrailingOffset 5

@implementation MPSumFunctionLayout

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

- (CTLineRef)line
{
    CTLineRef line = [self lineForPrivateCacheIndex:0 generator:^CTLineRef{
        return [self createLineForString:@"∑"];
    }];
    return line;
}

- (NSRect)localLineBounds
{
    NSRect lineBounds = CTLineGetBoundsWithOptions(self.line, 0);
    CGFloat width = MAX(MAX([self childLayoutAtIndex:0].bounds.size.width, [self childLayoutAtIndex:1].bounds.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 = -kSumFunctionStartExpressionOffset - childBounds.size.height;
    } else if (index == 1) {
        // Target Expression
        offset.x = localLineBounds.origin.x + localLineBounds.size.width / 2 - childBounds.size.width / 2;
        offset.y = localLineBounds.size.height + kSumFunctionTargetExpressionOffset;
    } 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;
}

- (NSIndexPath *)indexPathForMousePoint:(NSPoint)point
{
    // A single index is used to communicate back wether the
    // selection should be before or after the function.
    // A 0 means before, a 1 means after.
    for (NSUInteger index = 0; index < self.function.numberOfChildren; index++) {
        MPLayout *childLayout = [self childLayoutAtIndex:index];
        NSRect childBounds = childLayout.bounds;
        NSPoint childOffset = [self offsetOfChildLayoutAtIndex:index];
        childBounds.origin.x += childOffset.x;
        childBounds.origin.y += childOffset.y;
        if (NSMouseInRect(point, childBounds, self.flipped)) {
            NSPoint pointInChild = NSMakePoint(point.x + childOffset.x, point.y + childOffset.y);
            NSIndexPath *subPath = [childLayout indexPathForMousePoint:pointInChild];
            return [subPath indexPathByPreceedingIndex:index];
        }
    }
    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.size.width = MAX(bounds.size.width, targetExpressionBounds.size.width);
    bounds.size.height += targetExpressionBounds.size.height + kSumFunctionTargetExpressionOffset;
    
    bounds.size.width += kSumFunctionSumExpressionOffset + sumExpressionBounds.size.width;
    bounds.size.height = MAX(bounds.size.height, sumExpressionBounds.size.height);
    
    bounds.origin.y -= targetExpressionBounds.size.height + kSumFunctionStartExpressionOffset;
    bounds.size.width += kSumFunctionTrailingOffset;
    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);
    
    // Draw the start function
    MPLayout *startExpressionLayout = [self childLayoutAtIndex:0];
    NSPoint startExpressionLocation = NSMakePoint(localLineBounds.origin.x + localLineBounds.size.width / 2, 0);
    startExpressionLocation.x -= startExpressionLayout.bounds.size.width / 2;
    startExpressionLocation.y -= startExpressionLayout.bounds.size.height + kSumFunctionStartExpressionOffset;
    [startExpressionLayout drawAtPoint:startExpressionLocation];
    
    // Draw the target function
    MPLayout *targetExpressionLayout = [self childLayoutAtIndex:1];
    NSPoint targetExpressionLocation = NSMakePoint(localLineBounds.origin.x + localLineBounds.size.width / 2, localLineBounds.size.height);
    targetExpressionLocation.x -= targetExpressionLayout.bounds.size.width / 2;
    targetExpressionLocation.y += kSumFunctionTargetExpressionOffset;
    [targetExpressionLayout drawAtPoint:targetExpressionLocation];
    
    // Draw the sum function
    MPLayout *sumExpressionLayout = [self childLayoutAtIndex:2];
    CGFloat sumWidth = MAX(MAX(localLineBounds.origin.x + localLineBounds.size.width, startExpressionLayout.bounds.size.width), targetExpressionLayout.bounds.size.width);
    sumWidth += kSumFunctionSumExpressionOffset;
    [sumExpressionLayout drawAtPoint:NSMakePoint(sumWidth, 0)];
    
    CFRelease(line);
}

@end
