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

#import "MPParenthesisFunctionLayout.h"

#import "MPParenthesisFunction.h"


#define MPParenthesisFunctionOpeningParensOffset 2
#define MPParenthesisFunctionClosingParensOffset 0



@interface MPParenthesisFunctionLayout ()

- (NSBezierPath *)openingParens;
- (NSBezierPath *)closingParens;

- (NSBezierPath *)transformedOpeningParens;
- (NSBezierPath *)transformedClosingParens;

- (NSAffineTransform *)parenthesisTransform;

@end



@implementation MPParenthesisFunctionLayout

- (MPParenthesisFunction *)parenthesisFunction
{
    return (MPParenthesisFunction *)self.function;
}


- (NSBezierPath *)openingParens
{
    NSBezierPath *parens = [self objectForPrivateCacheIndex:0 generator:^id{
        CTLineRef line = [self createLineForString:@"("];
        CFArrayRef glyphRuns = CTLineGetGlyphRuns(line);
        CFRetain(glyphRuns);
        CTRunRef glyphRun = CFArrayGetValueAtIndex(glyphRuns, 0);
        CFRetain(glyphRun);
        
        CGGlyph *glyphs = malloc(1 * sizeof(CGGlyph));
        CTRunGetGlyphs(glyphRun, CFRangeMake(0, 1), glyphs);
        NSGlyph glyph = glyphs[0];
        
        NSBezierPath *path = [[NSBezierPath alloc] init];
        [path moveToPoint:NSZeroPoint];
        [path appendBezierPathWithGlyph:glyph
                                 inFont:self.font];
        
        CFRelease(line);
        CFRelease(glyphRuns);
        CFRelease(glyphRun);
        free(glyphs);
        
        return path;
    }];
    return parens;
}


- (NSBezierPath *)closingParens
{
    NSBezierPath *parens = [self objectForPrivateCacheIndex:1 generator:^id{
        CTLineRef line = [self createLineForString:@")"];
        CFArrayRef glyphRuns = CTLineGetGlyphRuns(line);
        CFRetain(glyphRuns);
        CTRunRef glyphRun = CFArrayGetValueAtIndex(glyphRuns, 0);
        CFRetain(glyphRun);
        
        CGGlyph *glyphs = malloc(1 * sizeof(CGGlyph));
        CTRunGetGlyphs(glyphRun, CFRangeMake(0, 1), glyphs);
        NSGlyph glyph = glyphs[0];
        
        NSBezierPath *path = [[NSBezierPath alloc] init];
        [path moveToPoint:NSZeroPoint];
        [path appendBezierPathWithGlyph:glyph
                                 inFont:self.font];
        
        CFRelease(line);
        CFRelease(glyphRuns);
        CFRelease(glyphRun);
        free(glyphs);
        
        return path;
    }];
    return parens;
}


- (NSBezierPath *)transformedOpeningParens
{
    NSBezierPath *parens = self.openingParens.copy;
    [parens transformUsingAffineTransform:self.parenthesisTransform];
    return parens;
}


- (NSBezierPath *)transformedClosingParens
{
    NSBezierPath *parens = self.closingParens.copy;
    [parens transformUsingAffineTransform:self.parenthesisTransform];
    return parens;
}


- (NSAffineTransform *)parenthesisTransform
{
    NSAffineTransform *transform = [NSAffineTransform transform];
    [transform scaleXBy:1
                    yBy:self.scaleFactor];
    return transform;
}


- (CGFloat)scaleFactor
{
    NSRect parensBounds = self.openingParens.bounds;
    NSRect expressionBounds = [self childLayoutAtIndex:0].bounds;
    CGFloat parensHeight = parensBounds.size.height;
    CGFloat expressionHeight = expressionBounds.size.height;
    if (expressionHeight <= parensHeight) {
        return 1.0;
    }
    return expressionHeight / parensHeight;
}


- (NSPoint)offsetOfChildLayoutAtIndex:(NSUInteger)index
{
    return NSMakePoint(self.openingParens.bounds.size.width + MPParenthesisFunctionOpeningParensOffset, 0);
}


- (NSIndexPath *)indexPathForLocalMousePoint:(NSPoint)point
{
    return [NSIndexPath indexPathWithIndex:0];
}


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


- (NSRect)generateBounds
{
    NSRect openingParensBounds = self.transformedOpeningParens.bounds;
    NSRect closingParensBounds = self.transformedClosingParens.bounds;
    NSRect bounds = [self childLayoutAtIndex:0].bounds;
    
    if (openingParensBounds.size.height > bounds.size.height) {
        bounds.size.height = openingParensBounds.size.height;
    }
    if (closingParensBounds.size.height > bounds.size.height) {
        bounds.size.height = closingParensBounds.size.height;
    }
    
    bounds.size.width += MPParenthesisFunctionOpeningParensOffset;
    bounds.size.width += openingParensBounds.size.width;
    bounds.size.width += MPParenthesisFunctionClosingParensOffset;
    bounds.size.width += closingParensBounds.size.width;
    
    return bounds;
}


- (void)draw
{
    NSBezierPath *openingParens = self.transformedOpeningParens;
    MPLayout *expressionLayout = [self childLayoutAtIndex:0];
    NSBezierPath *closingParens = self.transformedClosingParens;
    
    CGFloat x = 0;
    CGFloat y = -openingParens.bounds.origin.y + expressionLayout.bounds.origin.y;
    
    NSAffineTransform *transform = [NSAffineTransform transform];
    [transform translateXBy:0
                        yBy:y];
    [openingParens transformUsingAffineTransform:transform];
    [openingParens fill];
    x += openingParens.bounds.size.width;
    x += MPParenthesisFunctionOpeningParensOffset;
    x += expressionLayout.bounds.size.width;
    x += MPParenthesisFunctionClosingParensOffset;
    
    [transform translateXBy:x
                        yBy:0];
    [closingParens transformUsingAffineTransform:transform];
    [closingParens fill];
}

@end
