// 
//  Category.m
//  Flash2
//
//  Created by Nicholas Matsakis on 4/6/08.
//  Copyright 2008 Nicholas Matsakis. All rights reserved.
//

#import "Models.h"
#import "OxNSString.h"
#import "OxDebug.h"
#import "OxNSObject.h"

@implementation Category 

#pragma mark Core Data Properties and Relationships

@dynamic order;
@dynamic name;
@dynamic regularExpression;
@dynamic superCategory;
@dynamic relationshipsFrom;
@dynamic methods;
@dynamic relationshipsTo;
@dynamic rootCategoryOf;
@dynamic subCategories;
@dynamic language;

#pragma mark Virtual Keys

- (NSSet*) computeApplicableRelationships:(OxMemoize*)memo
{
    // Could use some magic here to make this more invisible!
    NSSet *relationshipsFrom = [memo valueForKeyPath:K_CATEGORY_RELATIONSHIPS_FROM
                                            ofObject:self];
    NSSet *superApplicable;
    id superCategory = [memo valueForKeyPath:K_CATEGORY_SUPER_CATEGORY
                                    ofObject:self];
    if (superCategory != nil)
        superApplicable = [memo valueForKeyPath:K_CATEGORY_APPLICABLE_RELATIONSHIPS
                                       ofObject:superCategory];
    else
        superApplicable = [NSSet set];

    OxLog(@"computingApplicableRelationships for %@", [self shortDescription]);
    OxLog(@"  superApplicable count = %d", [superApplicable count]);
    OxLog(@"  relationshipsFrom count = %d", [relationshipsFrom count]);
    
    return [superApplicable setByAddingObjectsFromSet:relationshipsFrom];
}

- (NSSet*) applicableRelationships
{
    if (m_applicableRelationships == nil)
        m_applicableRelationships = [OxMemoize new];
    return [m_applicableRelationships computeKey:K_CATEGORY_APPLICABLE_RELATIONSHIPS
                                        ofObject:self 
                                    withSelector:@selector(computeApplicableRelationships:)];
}

#pragma mark Other Methods

+ (void) initialize {
    [self setKeys:[NSArray arrayWithObject:@"name"] triggerChangeNotificationsForDependentKey:@"indentedName"];
}

- (BOOL) isRootCategory {
    return (self.language.rootCategory == self);
}

- (NSInteger) calculateDepth
{
    int depth = 0;
    Category *c = self;
    while (c != nil) {
        depth++;
        c = c.superCategory;
    }
    return depth;
}

- (NSString*) indentedName
{
    int depth = [self calculateDepth];
    NSString *indent = [@"  " stringByRepeating:depth-1];
    return [NSString stringWithFormat:@"%@%@", indent, self.name];
}

- (void) setIndentedName:(NSString*)name 
{
    self.name = [name strip];
}

- (NSString*) languageAndName 
{
    return [NSString stringWithFormat:@"%@: %@", self.language.name, self.name];
}

- (CategoryMethod*) methodWithName:(NSString*)name
{
    for (CategoryMethod *cm in self.methods)
        if ([cm.name isEqual:name])
            return cm;
    return [self.superCategory methodWithName:name]; // if nil, will return nil
}

- (CategoryMethod*) methodDefiningRelationshipWithName:(NSString*)relName
{
    for (CategoryMethod *cm in self.methods)
        if ([cm.definesRelationship.name isEqual:relName])
            return cm;
    if (self.superCategory)
        return [self.superCategory methodDefiningRelationshipWithName:relName];    
    return nil;
}

@end
