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

#import "MPFunction.h"

#import "MPExpression.h"
#import "MPRangePath.h"
#import "NSIndexPath+MPAdditions.h"

#import "MPFunctionTerm.h"



@implementation MPFunction

#pragma mark Creation Methods


- (instancetype)init
{
    self = [super init];
    if (self) {
        for (NSString *key in self.childrenAccessors) {
            MPExpression *emptyExpression = [[MPExpression alloc] init];
            emptyExpression.parent = self;
            [self setValue:emptyExpression
                    forKey:key];
        }
    }
    return self;
}


#pragma mark Working With the Expression Tree


- (MPExpression *)rootExpression
{
    return [self.parent rootExpression];
}


- (NSIndexPath *)indexPath
{
    if (!self.parent) {
        return nil;
    }
    NSUInteger selfIndex = [self.parent indexOfElement:self];
    return [[self.parent indexPath] indexPathByAddingIndex:selfIndex];
}


- (NSUInteger)numberOfChildren
{
    return self.childrenAccessors.count;
}


- (MPExpression *)childAtIndex:(NSUInteger)index
{
    return [self valueForKey:self.childrenAccessors[index]];
}


- (void)setChild:(MPExpression *)child
         atIndex:(NSUInteger)index
{
    [[self valueForKey:self.childrenAccessors[index]] setParent:nil];
    [self setValue:child
            forKey:self.childrenAccessors[index]];
    child.parent = self;
    [self didChangeChildAtIndex:index];
}


- (NSArray *)children
{
    NSUInteger childCount = [self numberOfChildren];
    NSMutableArray *children = [[NSMutableArray alloc] initWithCapacity:childCount];
    for (NSInteger i = 0; i < childCount; i++) {
        [children addObject:[self childAtIndex:i]];
    }
    return [children copy];
}


- (NSUInteger)indexOfChild:(MPExpression *)child
{
    
    NSUInteger index = 0;
    for (; index < [self numberOfChildren]; index++) {
        if ([self childAtIndex:index] == child) {
            return index;
        }
    }
    return NSNotFound;
}


- (id)elementAtIndexPath:(NSIndexPath *)indexPath
{
    if (indexPath.length == 0) {
        return self;
    }
    MPExpression *child = [self childAtIndex:[indexPath indexAtPosition:0]];
    return [child elementAtIndexPath:[indexPath indexPathByRemovingFirstIndex]];
}


#pragma mark Notifications


- (void)didChangeElementsInRangePath:(MPRangePath *)rangePath
                   replacementLength:(NSUInteger)replacementLength
{
    NSUInteger selfIndex = [self.parent indexOfElement:self];
    MPRangePath *newPath = MPMakeRangePath([rangePath.location indexPathByPreceedingIndex:selfIndex], rangePath.length);
    [self.parent changedElementsInRangePath:newPath
                            replacementLength:replacementLength];
}


- (void)didChangeChildAtIndex:(NSUInteger)index
{
    MPRangePath *path = [[MPRangePath alloc] initWithRange:NSMakeRange(index, 1)];
    [self didChangeElementsInRangePath:path
                     replacementLength:1];
}


#pragma mark Evaluating Functions


- (BOOL)expectsVariableDefinitionInChildAtIndex:(NSUInteger)index
{
    return NO;
}


#pragma mark Working With Functions


- (NSString *)description
{
    return @"[]";
}


#pragma mark - NSCopying


- (id)copyWithZone:(NSZone *)zone
{
    id copy = [[self.class allocWithZone:zone] init];
    for (NSString *key in self.childrenAccessors) {
        MPExpression *child = [[self valueForKey:key] copy];
        [copy setValue:child forKey:key];
    }
    return copy;
}


#pragma mark - NSCoding


- (id)initWithCoder:(NSCoder *)aDecoder
{
    self = [super init];
    if (self) {
        NSArray *children = [aDecoder decodeObject];
        NSInteger index = 0;
        for (MPExpression *child in children) {
            [self setChild:child atIndex:index];
            ++index;
        }
    }
    return self;
}


- (void)encodeWithCoder:(NSCoder *)aCoder
{
    [aCoder encodeObject:self.children];
}


#pragma mark - MPExpressionElement


- (BOOL)isString
{
    return NO;
}


- (BOOL)isFunction
{
    return YES;
}


- (NSUInteger)length
{
    return 1;
}

@end
