//
//  PWTreeControllerNode.m
//  PWTreeControllerDemo
//
//  Created by Frank Illenberger on 04.03.06.
//  Copyright 2006 ProjectWizards, Melle, Germany. 
//

#import "PWTreeControllerNode.h"
#import "PWTreeController.h"
#import "PWTreeController-Private.h"
#import "PWObservationInfo.h"

#define PWTreeControllerSubNodesChangeContext @"PWTreeControllerSubNodesChange"
#define PWTreeControllerIsLeafChangeContext @"PWTreeControllerIsLeafChange"

@implementation PWTreeControllerNode

- (id)initWithTreeController:(PWTreeController *)controller observedObject:(id)object parentNode:(PWTreeControllerNode *)parent
{
	[super init];
	treeController = controller;
	parentNode = parent;
	observedObject = [object retain];
	CFDictionarySetValue(treeController->nodesForObjects, observedObject, self);
	
	if(treeController->childrenKeyPath)
	{
		[observedObject addObserver:self forKeyPath:treeController->childrenKeyPath options: NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:PWTreeControllerSubNodesChangeContext];	
		isObservingSubNodes = YES;
	}
	
	if(treeController->isLeafKeyPath)
	{
		[observedObject addObserver:self forKeyPath:treeController->isLeafKeyPath options: NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:PWTreeControllerIsLeafChangeContext];
		isObservingLeafState = YES;	
	}
	
	[self addAttributeObservers:treeController->attributeObservers recurse:NO];
	isObservingAttributes = YES;
	return self;
}

- (void)createSubNodeForObjects:(NSSet *)objects
{
	NSEnumerator *e = [objects objectEnumerator];
	id object;
	while (object = [e nextObject]) 
	{
		PWTreeControllerNode *node = [[PWTreeControllerNode alloc] initWithTreeController:treeController observedObject:object parentNode:self];
		[subNodes addObject:node];
		[node release];
	}
	[filteredSubNodes release];
	filteredSubNodes = nil;
	needsResort = YES;
}

- (void)removeSubNodeForObjects:(NSSet *)objects
{
	NSEnumerator *e = [objects objectEnumerator];
	id object;
	while (object = [e nextObject]) 
	{
		PWTreeControllerNode *node = (PWTreeControllerNode *)CFDictionaryGetValue(treeController->nodesForObjects,  object);
		[subNodes removeObject:node];
	}
	[filteredSubNodes release];
	filteredSubNodes = nil;
	needsResort = YES;
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
	if(context == PWTreeControllerSubNodesChangeContext)
	{
		[treeController willChangeSubNodesOfNode:self];
		if(subNodes)
		{
			int kind = [[change objectForKey:NSKeyValueChangeKindKey] intValue];
			id new = [change objectForKey:NSKeyValueChangeNewKey];
			if(kind == NSKeyValueChangeSetting || kind == NSKeyValueChangeReplacement || ![new count] )
				[self prune];
			else if(kind == NSKeyValueChangeInsertion)
				[self createSubNodeForObjects:new];
			else if(kind == NSKeyValueChangeRemoval)
				[self removeSubNodeForObjects:new];
		}
		determinedIsLeafValue = NO;	
		[treeController didChangeSubNodesOfNode:self];
	}
	else if(context == PWTreeControllerIsLeafChangeContext)
	{
		BOOL newIsLeaf = [[observedObject valueForKeyPath:treeController->isLeafKeyPath] boolValue];
		if(!determinedIsLeafValue || newIsLeaf!=isLeaf)
		{
			[treeController willChangeLeafStateOfNode:self];
			if(isLeaf && subNodes)
				[self prune];
			determinedIsLeafValue = YES;	
			[treeController didChangeLeafStateOfNode:self];
		}
	}
}

- (void)addAttributeObservers:(NSArray *)observers recurse:(BOOL)recurse
{
	int count = [observers count];
	for(int index=0; index<count; index++)
	{
		PWObservationInfo *o = [observers objectAtIndex:index];
		[observedObject addObserver:o->observer forKeyPath:o->keyPath options:o->options context:o->context];
	}	
	
	if(recurse)
	{
		int count = [subNodes count];
		for(int index=0; index<count; index++)
			[[subNodes objectAtIndex:index] addAttributeObservers:observers recurse:recurse];	
	}
}

- (void)removeAttributeObservers:(NSArray *)observers recurse:(BOOL)recurse
{
	int count = [observers count];
	for(int index=0; index<count; index++)
	{
		PWObservationInfo *o = [observers objectAtIndex:index];
		[observedObject removeObserver:o->observer forKeyPath:o->keyPath];
	}	

	if(recurse)
	{
		int count = [subNodes count];
		for(int index=0; index<count; index++)
			[[subNodes objectAtIndex:index] removeAttributeObservers:observers recurse:recurse];	
	}
}

- (void)removeObservers
{
	if(isObservingAttributes)
	{
		[self removeAttributeObservers:treeController->attributeObservers recurse:NO];
		isObservingAttributes = NO;		
	}
	if(isObservingSubNodes)
	{
		[observedObject removeObserver:self forKeyPath:treeController->childrenKeyPath ];		
		isObservingSubNodes = NO;
	}
	if(isObservingLeafState)
	{
		[observedObject removeObserver:self forKeyPath:treeController->isLeafKeyPath ];		
		isObservingLeafState = NO;
	}
}

- (void)dealloc
{
	if(treeController)
	{
		[self removeObservers];
		if(CFDictionaryGetValue(treeController->nodesForObjects,  observedObject)==self)
			CFDictionaryRemoveValue(treeController->nodesForObjects, observedObject);
	}
	[observedObject release];
	[subNodes release];
	[filteredSubNodes release];
	[super dealloc];
}

- (NSArray *) childNodes
{
	return subNodes;
}

- (NSArray *)subNodes
{
	if(isLeaf)
		return nil;
	else if(!subNodes)
	{
		id collection = [observedObject valueForKeyPath:[treeController childrenKeyPath]];
		NSArray *array = [collection isKindOfClass:[NSArray class]] ? collection : [collection allObjects];
		subNodes = [[treeController createNodesFromObservedObjectsArray:array parentNode:self] retain];
	}
	else if(needsResort)
	{
		NSArray *descs = [treeController observedObjectsSortDescriptors];
		[subNodes sortUsingDescriptors:descs];
		[filteredSubNodes release];
		filteredSubNodes = nil;
		needsResort = NO;
	}
	return subNodes;
}

- (PWTreeControllerNode *)parentNode
{
	return parentNode;
}

- (NSArray *)filteredSubNodes
{
	if(!determinedIsLeafValue || !isLeaf)
	{
		if(needsResort)
		{
			[filteredSubNodes release];
			filteredSubNodes = nil;
		}
		if(!filteredSubNodes)
		{
			NSArray *nodes = [self subNodes];
			filteredSubNodes = [[NSMutableArray alloc] init];
			int count = [nodes count];
			for(int index=0; index<count; index++)
			{
				PWTreeControllerNode *subNode = [nodes objectAtIndex:index];
				if([treeController->filteredObjectsAndAncestors containsObject:[subNode observedObject]])
					[filteredSubNodes addObject:subNode];
			}
		}
	}
	return filteredSubNodes;
}

- (NSArray *)arrangedSubNodes
{
	return treeController->filterPredicate ? [self filteredSubNodes] : [self subNodes];
}

- (BOOL)isLeaf
{
	if(!determinedIsLeafValue)
	{
		if(treeController->isLeafKeyPath && !determinedIsLeafValue)
			isLeaf = [[observedObject valueForKeyPath:treeController->isLeafKeyPath] boolValue];
		else if(subNodes)
			isLeaf = [subNodes count]==0;
		else
			isLeaf = [[observedObject valueForKeyPath:treeController->childrenKeyPath] count]==0;
		determinedIsLeafValue = YES;
	}
	return isLeaf;
}

- (id)observedObject
{
	return observedObject;
}

- (id)representedObject
{
	return observedObject;
}


- (void)setNeedsResort:(BOOL)needs
{
	needsResort = needs;
	int count = [subNodes count];
	for(int index=0; index<count; index++)
		[[subNodes objectAtIndex:index] setNeedsResort:needs];
}

- (void)treeControllerWillDealloc
{
	[self removeObservers];
	treeController = nil;
	int count = [subNodes count];
	for(int index=0; index<count; index++)
		[[subNodes objectAtIndex:index] treeControllerWillDealloc];	
}

- (void)treeControllerDidChangeLeafKeyPath:(NSString *)oldKeyPath
{
	if(oldKeyPath)
		[observedObject removeObserver:self forKeyPath:oldKeyPath];		
	if(treeController->isLeafKeyPath)
		[observedObject addObserver:self forKeyPath:treeController->isLeafKeyPath options: 0 context:PWTreeControllerIsLeafChangeContext];		
	int count = [subNodes count];
	for(int index=0; index<count; index++)
		[[subNodes objectAtIndex:index] treeControllerDidChangeLeafKeyPath:oldKeyPath];	
	[self prune];
}

- (void)invalidate
{
	[self removeObservers];
	if(CFDictionaryGetValue(treeController->nodesForObjects,  observedObject)==self)
		CFDictionaryRemoveValue(treeController->nodesForObjects, observedObject);
	int count = [subNodes count];
	for(int index=0; index<count; index++)
		[[subNodes objectAtIndex:index] invalidate];
	[subNodes autorelease];
	subNodes = nil;
	[filteredSubNodes autorelease];
	filteredSubNodes = nil;
	determinedIsLeafValue = NO;
}

- (void)prune
{
	[subNodes makeObjectsPerformSelector:@selector(invalidate)];
	[subNodes autorelease];
	subNodes = nil;
	[filteredSubNodes autorelease];
	filteredSubNodes = nil;
	determinedIsLeafValue = NO;
}

- (void)flushFilteredSubNodes
{
	[filteredSubNodes release];
	filteredSubNodes = nil;
	int count = [subNodes count];
	for(int index=0; index<count; index++)
		[[subNodes objectAtIndex:index] flushFilteredSubNodes];	
}

- (void)createAllSubNodes
{
	[self subNodes];
	int count = [subNodes count];
	for(int index=0; index<count; index++)
		[[subNodes objectAtIndex:index] createAllSubNodes];	
}

- (void) indexPath
{
    printf( "indexPath");
}

- (int) depth
{
	if (parentNode) return [parentNode depth]+1;
	return 0;
}

-(NSFont *) font
{
	int size=18-[self depth]*2;
	if (size < 9) size=9;
	return [NSFont fontWithName:@"Helvetica" size: size];	
}


@end

