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

#import "MPFunctionsViewController.h"

#import "MPFunction.h"
#import "MPFractionFunction.h"
#import "MPParenthesisFunction.h"
#import "MPPowerFunction.h"
#import "MPSumFunction.h"

#import "MPFunctionLayout.h"

#import "NSString+MPExpressionElement.h"



@class MPFunctionsCollectionView, MPFunctionTemplateView, MPFunctionTemplateItem;


@interface MPFunctionsCollectionView : NSCollectionView

@property (nonatomic, weak) MPFunctionTemplateItem *hoverItem;

@property (nonatomic, weak) id target;
@property (nonatomic) SEL action;

@end



@interface MPFunctionTemplateView : NSView

@property (nonatomic, strong) MPFunction *functionTemplate;
@property (readonly, nonatomic, strong) MPFunctionLayout *functionTemplateLayout;
@property (nonatomic, strong) NSTrackingArea *trackingArea;
@property (nonatomic) BOOL mouseOver;

@end



@interface MPFunctionTemplateItem : NSCollectionViewItem

@property (nonatomic, copy) NSString *templateName;

@end



@implementation MPFunctionsCollectionView

- (void)mouseDown:(NSEvent *)theEvent
{
}


- (void)mouseUp:(NSEvent *)theEvent
{
    NSPoint pointInView = [self convertPoint:theEvent.locationInWindow
                                    fromView:nil];
    for (NSUInteger index = 0; index < self.content.count; index++) {
        NSCollectionViewItem *viewItem = [self itemAtIndex:index];
        if (NSMouseInRect(pointInView, viewItem.view.frame, self.isFlipped)) {
            if (self.target && self.action) {
                [self.target performSelector:self.action
                                  withObject:[[viewItem.representedObject objectForKey:@"function" ] copy]
                                  afterDelay:0.0];
            }
            break;
        }
    }
}

@end



@implementation MPFunctionTemplateView

- (void)updateTrackingAreas
{
    if (!self.trackingArea) {
        self.trackingArea = [[NSTrackingArea alloc] initWithRect:self.bounds
                                                         options:NSTrackingMouseEnteredAndExited|NSTrackingActiveInKeyWindow|NSTrackingInVisibleRect
                                                           owner:self
                                                        userInfo:nil];
        [self addTrackingArea:self.trackingArea];
    }
    [super updateTrackingAreas];
}


- (void)mouseEntered:(NSEvent *)theEvent
{
    self.mouseOver = YES;
    self.needsDisplay = YES;
}


- (void)mouseExited:(NSEvent *)theEvent
{
    self.mouseOver = NO;
    self.needsDisplay = YES;
}


- (void)setFunctionTemplate:(MPFunction *)functionTemplate
{
    _functionTemplate = functionTemplate;
    _functionTemplateLayout = nil;
}


@synthesize functionTemplateLayout = _functionTemplateLayout;

- (MPFunctionLayout *)functionTemplateLayout
{
    
    if (!_functionTemplateLayout) {
        _functionTemplateLayout = [MPFunctionLayout functionLayoutForFunction:self.functionTemplate
                                                                       parent:nil];
        _functionTemplateLayout.usesSmallSize = YES;
    }
    return _functionTemplateLayout;
}


- (NSSize)intrinsicContentSize
{
    return [self.functionTemplateLayout bounds].size;
}


- (BOOL)isOpaque
{
    return NO;
}


- (void)drawRect:(NSRect)dirtyRect
{
    if (self.mouseOver) {
        [[NSColor selectedTextBackgroundColor] set];
        NSBezierPath *background = [NSBezierPath bezierPathWithRoundedRect:self.bounds
                                                                   xRadius:10
                                                                   yRadius:10];
        [background fill];
    }
    [[NSColor textColor] set];
    NSPoint origin = NSMakePoint((self.bounds.size.width - self.functionTemplateLayout.bounds.size.width) / 2, (self.bounds.size.height - self.functionTemplateLayout.bounds.size.height) / 2);
    origin.y -= self.functionTemplateLayout.bounds.origin.y;
    [self.functionTemplateLayout drawAtPoint:origin];
}

@end



@implementation MPFunctionTemplateItem

static void *MPFunctionTemplateViewMouseOverContext = @"MPFunctionTemplateViewMouseOverContext";


- (id)awakeAfterUsingCoder:(NSCoder *)aDecoder
{
    return [super awakeAfterUsingCoder:aDecoder];
}


- (void)observeValueForKeyPath:(NSString *)keyPath
                      ofObject:(id)object
                        change:(NSDictionary *)change
                       context:(void *)context
{
    if (context == MPFunctionTemplateViewMouseOverContext) {
        MPFunctionTemplateView *view = (MPFunctionTemplateView *)self.view;
        ((MPFunctionsCollectionView *)self.collectionView).hoverItem = view.mouseOver ? self : nil;
    } else {
        [super observeValueForKeyPath:keyPath
                             ofObject:object
                               change:change
                              context:context];
    }
}


- (void)setRepresentedObject:(id)representedObject
{
    MPFunctionTemplateView *view = (MPFunctionTemplateView *)self.view;
    view.functionTemplate = [representedObject objectForKey:@"function"];
    self.templateName = [representedObject objectForKey:@"name"];
    [view addObserver:self
           forKeyPath:@"mouseOver"
              options:0
              context:MPFunctionTemplateViewMouseOverContext];
    [super setRepresentedObject:representedObject];
}

@end



@interface MPFunctionsViewController ()

@end



@implementation MPFunctionsViewController

- (id)init
{
    return [self initWithNibName:@"MPFunctionsViewController"
                          bundle:[NSBundle bundleForClass:[self class]]];
}


- (void)awakeFromNib
{
    MPFunction *sumFunction = [[MPSumFunction alloc] init];
    MPFunction *parenthesisFunction = [[MPParenthesisFunction alloc] init];
    MPFunction *powerFunction = [[MPPowerFunction alloc] init];
    MPPowerFunction *squareFunction = [[MPPowerFunction alloc] init];
    squareFunction.exponentExpression = [[MPExpression alloc] initWithElement:@"2"];
    MPPowerFunction *cubicFunction = [[MPPowerFunction alloc] init];
    cubicFunction.exponentExpression = [[MPExpression alloc] initWithElement:@"3"];
    MPFractionFunction *fractionFunction = [[MPFractionFunction alloc] init];
    self.functionPrototypes = @[
                                @{@"function": sumFunction,
                                  @"name": NSLocalizedString(@"Sum", @"Sum Function Name")},
                                @{@"function": parenthesisFunction,
                                  @"name": NSLocalizedString(@"Parenthesis", @"Parenthesis Function Name")},
                                @{@"function": squareFunction,
                                  @"name": NSLocalizedString(@"Square", @"Square Function Name")},
                                @{@"function": cubicFunction,
                                  @"name": NSLocalizedString(@"Cubic", @"Cubic Function Name")},
                                @{@"function": powerFunction,
                                  @"name": NSLocalizedString(@"Power", @"Power Function Name")},
                                @{@"function": fractionFunction,
                                  @"name": NSLocalizedString(@"Fraction", @"Fraction Function Name")}
                                ];
    [self.collectionView addObserver:self
                          forKeyPath:@"hoverItem"
                             options:0
                             context:MPCollectionViewHoverItemChangeContext];
    ((MPFunctionsCollectionView *)self.collectionView).target = self.target;
    ((MPFunctionsCollectionView *)self.collectionView).action = self.action;
}


static void *MPCollectionViewHoverItemChangeContext = @"MPCollectionViewHoverItemChangeContext";


- (void)setView:(NSView *)view
{
    [super setView:view];
}


- (void)setTarget:(id)target
{
    _target = target;
    if (self.collectionView) {
        ((MPFunctionsCollectionView *)self.collectionView).target = target;
    }
}


- (void)setAction:(SEL)action
{
    _action = action;
    if (self.collectionView) {
        ((MPFunctionsCollectionView *)self.collectionView).action = action;
    }
}


- (void)observeValueForKeyPath:(NSString *)keyPath
                      ofObject:(id)object
                        change:(NSDictionary *)change
                       context:(void *)context
{
    if (context == MPCollectionViewHoverItemChangeContext) {
        self.currentDescription = ((MPFunctionsCollectionView *)self.collectionView).hoverItem.templateName;
    } else {
        [super observeValueForKeyPath:keyPath
                             ofObject:object
                               change:change
                              context:context];
    }
}

@end
