/** WARNING: Personal notes that are vague and may change, move or become part
	of another framework.

	Rendering tree is an extension of renderer support, this extension is 
	useful essentially in imaging applications either vector or bitmap based.

	Rendering is the step which precedes display and encompass both layout and
	real time graphics computation.
	A renderer tree would be roughly identical to GEGL model.
	Layout item tree and renderer tree form two parallel trees which are 
	bridged together and ruled by layout items. 
	At each layout item node, a renderer branch is connected.
	Both trees are visited together from top to bottom at rendering time.
	At rendering time, a visitor object which encapsulates the rendering state
	is passed through layout items:
	- it enters a layout item
	- it visits the item renderer branch and computes it if needed
	- it memorizes the first renderer directly connected to the layout item
	- it quits the layout item
	- it enters a second layout item
	- it checks whether the first renderer of the layout item has a second 
	input if we put aside renderer branch which plays the first input role; if
	no second input is present, it uses the last memorized renderer in this 
	role
	- it removes the last memorized renderer of the second input if necessary
	- it memorizes the renderer connected to the second layout
	- it quits the layout item
 */


== Random API ideas ==

// TODO: For each document set the editor tool. Eventually offer a 
// delegate method either through ETTool or ETDocumentManager to give 
// more control over this...
+ (void) setEditorTool: (id)anTool
{
	//[documentLayout setAttachedTool: anTool];
}

// TODO: Think about...
+ (void) setEditorTargetItems: (NSArray *)items
{

}

// TODO: Implement
//- (void) didBecomeActive: (ETTool *)prevTool;
// or
/*- (void) willBecomeActive
{
	ETTool *activeTool = [ETTool activeTool];
	BOOL isToolReplacement = ([activeTool isSelectTool] && [[activeTool layoutOwner] isEqual: [self layoutOwner]]);
	
	if (isToolReplacement)
		[self setAllowedDragUTIs: [activeTool allowedDragUTIs]];
}*/
// or rather take the values from the controller when attaching the tool for the first time. or cache a select tool prototype in the controller? Well need a general mechanism to store tool prototypes anyway…
// -[ETController setPrototype: forToolClass:]?

// TODO: Inspection and ETSelectTool
/* Returns inspector based on selection unlike ETLayoutItem.

If a custom inspector hasn't been set by calling -setInspector:, the inspector 
set on the base item is retrieved. If the option/alt modifier key is pressed, 
a copy of the inspector is returned rather reusing the existing instance as 
usual. This facility allows to easily inspect two items with two distinct 
inspectors, even if these layout items belong to the same base item. At UI level, 
the user can press the option/alt key when choosing Inspect in a menu. */

/** ETlayoutItem has no delegate but rather used the delegate of the closest 
	container ancestor.
	Implements this method if you set values in aggregate views or cells. For
	example, when you have a mixed icon text cell, you would write:
	if ([property isEqual: kPropertyName])
	{
		[[item cell] setText: value];
		[[item cell] setImage: [item valueForProperty: @"icon"];
	}
	Be careful with property because it can be a key path so you may better 
	to always retrieve the last component.
	Binding can be used instead of this method if you prefer.
	An other alternative is to subclass ETLayoutItem and overrides method
	-setValue:forProperty:. But the purpose of this delegate is precisely to 
	avoid subclassing burden. */
@interface ETLayoutItem (ETLayoutItemDelegate)
- (void) layoutItem: (ETLayoutItem *)item setValue: (id)value forProperty: (NSString *)property;
@end

- (void) setDraggingAllowedForTypes: (NSArray *)types;
- (NSArray *) allowedDraggingTypes;
- (void) setDroppingAllowedForTypes: (NSArray *)types;
- (NSArray *) allowedDroppingTypes;
- (void) setDropTargetTypes: (NSArray *)types;
- (NSArray *)dropTargetTypes;

- (ETLayoutAlignment) layoutAlignment;
- (void) setLayoutAlignment: (ETLayoutAlignment)alignment;

- (ETLayoutOverflowStyle) overflowStyle;
- (void) setOverflowStyle: (ETLayoutOverflowStyle);

- (id) scaleItemsToRect: (NSRect)rect;
- (id) scaleItemsToFit: (id)sender;
// This method is equivalent to calling -setItemScaleFactor with 1.0 value
- (id) scaleItemsToActualSize: (id)sender;
- (float) itemRotationAngle;
- (void) setItemRotationAngle: (float)factor;

@interface NSObject (ETContainerSource)

/* Coordinates retrieval useful with containers oriented towards graphics and 
   spreadsheet */
- (ETVector *) container: (ETContainer *)container 
	locationForItem: (ETLayoutItem *)item;
- (void) container: (ETContainer *)container setLocation: (ETVector *)vectorLoc 
	forItem: (ETLayoutItem *)item;

/* Extra infos */
- (NSArray *) editableItemPropertiesInContainer: (ETContainer *)container;
- (NSView *) container: (ETContainer *)container 
	editorObjectForProperty: (NSString *)property ;
- (int) firstVisibleItemInContainer: (ETContainer *)container;
- (int) lastVisibleItemInContainer: (ETContainer *)container;

/* Pick and drop support and Bindings support by index */
/* When operation is a pick and drop one (either copy/paste or drag/drop), 
   - 'container:addItems:operation:' is called when no selection is set
   - 'container:insertItems:atIndexes:operation:' is called when a selection 
      exists */
/* These methods make also possible to use your data source with bindings if 
   you use the specifically designed controller ETSourceController */
- (BOOL) container: (ETContainer *)container addItems: (NSArray *)items 
	operation: (ETEvent *)op;
- (BOOL) container: (ETContainer *)container insertItems: (NSArray *)items 
	atIndexes: (NSIndexSet *)indexes operation: (ETEvent *)op;
- (BOOL) container: (ETContainer *)container removeItems: (NSArray *)items 
	atIndexes: (NSIndexSet *)indexes operation: (ETEvent *)op;

/* Pick and drop support and Bindings support by index path */
- (BOOL) container: (ETContainer *)container addItems: (NSArray *)items 
	atPath: (NSIndexPath *)path operation: (ETEvent *)op;
- (BOOL) container: (ETContainer *)container insertItems: (NSArray *)items 
	atPaths: (NSArray *)paths operation: (ETEvent *)op;
- (BOOL) container: (ETContainer *)container 
	removeItemsAtPaths: (NSArray *)paths operation: (ETEvent *)op;

/* Advanced pick and drop support 
   Only needed if you want to override pick and drop support. Useful to get more
   control over drag an drop. */
- (BOOL) container: (ETContainer *)container handlePick: (ETEvent *)event 
	forItems: (NSArray *)items pickboard: (ETPickboard *)pboard;
- (BOOL) container: (ETContainer *)container handleAcceptDrop: (id)dragInfo 
	forItems: (NSArray *)items on: (id)item pickboard: (ETPickboard *)pboard;
- (BOOL) container: (ETContainer *)container handleDrop: (id)dragInfo 
	forItems: (NSArray *)items on: (id)item pickboard: (ETPickboard *)pboard;

// TODO: Extend the informal protocol to propogate group/ungroup actions in 
// they can be properly reflected on model side.

@end

@interface ETContainer (ETContainerDelegate)

- (void) containerShouldStackItem: (NSNotification *)notif;
- (void) containerDidStackItem: (NSNotification *)notif;
- (void) containerShouldGroupItem: (NSNotification *)notif;
- (void) containerDidGroupItem: (NSNotification *)notif;
// NOTE: We use a double action instead of the delegate to handle double-click
//- (void) containerDoubleClickedItem: (NSNotification *)notif;

@end


== Special Group Access Ideas in ETLayoutItemFactory ==

/** Returns the absolute root group usually located in the UI server.

This root group representing the whole environment is the only layout item 
with truly no parent.

WARNING: Not yet implemented. */
- (id) rootGroup
{
	return nil;
}

//static ETLayoutItemGroup *localRootGroup = nil;

/** Returns the local root group which represents the current work context or 
application.

WARNING: You should avoid to use this method. For now, it returns -windowGroup 
as the local root group, but this probably won't be the case in the future. 
This method might also removed. -windowGroup is the method you are encouraged 
to use.

When the UI server is running, the local root group is inserted as a child in a  
parent located in the UI server process. When no UI server is available, the 
local root group will have no parent.
 
ETApplication returns the same item when you call -layoutItem method 
(unless the method has been overriden). This might not hold in the future either.  */
- (id) localRootGroup
{
	// TODO: Should add -windowGroup... but how the top part of the layout 
	// item tree is organized needs to be worked out in details.
#if 0
	if (localRootGroup == nil)
	{
		localRootGroup = [[ETLayoutItemGroup alloc] init];
		[localRootGroup setName: _(@"Application")];
		[localRootGroup addItem: [self windowGroup]];
	}

	return localRootGroup;
#endif 

	return [self windowGroup];
}

/** Returns the item representing the main screen.

TODO: Implement or rethink... */
- (id) screen
{
	return nil;
}

/** Returns the item group representing all screens available (usually the 
screens connected to the computer).

TODO: Implement or rethink... */
- (id) screenGroup
{
	return nil;
}

/** Returns the item group representing the active project.

TODO: Implement or rethink... */
- (id) project
{
	return nil;
}

/** Returns the item group representing all projects. 

TODO: Implement or rethink... */
- (id) projectGroup
{
	return nil;
}


== Initial Stacking Support in ETLayoutItemGroup ==

/* Stacking */

+ (NSSize) stackSize
{
	return NSMakeSize(200, 200);
}

- (ETLayout *) stackedItemLayout
{
	return _stackedLayout;
}

- (void) setStackedItemLayout: (ETLayout *)layout
{
	ASSIGN(_stackedLayout, layout);
}

- (ETLayout *) unstackedItemLayout
{
	return _unstackedLayout;
}

- (void) setUnstackedItemLayout: (ETLayout *)layout
{
	ASSIGN(_unstackedLayout, layout);
}

- (void) setIsStack: (BOOL)flag
{
	if (_isStack == NO)
	{
		[self setItemScaleFactor: 0.7];
		[self setSize: [ETLayoutItemGroup stackSize]];
	}
		
	_isStack = flag;
}

- (BOOL) isStack
{
	return _isStack;
}

/** Returns YES when the receiver is a collapsed stack, otherwise returns NO. */
- (BOOL) isStacked
{
	return [self isStack] && [[self layout] isEqual: [self stackedItemLayout]];
}

- (void) stack
{
	/* Turn item group into stack if necessary */
	[self setIsStack: YES];
	[self reloadIfNeeded];
	[self setLayout: [self stackedItemLayout]];
}

- (void) unstack
{
	/* Turn item group into stack if necessary */
	[self setIsStack: YES];
	[self reloadIfNeeded];
	[self setLayout: [self unstackedItemLayout]];
}


== ETView/ETContainer Archiving Code ==

- (id) archiver: (NSKeyedArchiver *)archiver willEncodeObject: (id)object
{
	ETDebugLog(@"---- Will encode %@", object);
	
	/* Don't encode layout view and item views */
	if ([object isEqual: [self subviews]])
	{
		id archivableSubviews = [object mutableCopy];
		id itemViews = [[self items] valueForKey: @"displayView"];

		ETDebugLog(@"> Won't be encoded");	
		if ([self layoutView] != nil)	
			[archivableSubviews removeObject: [self layoutView]];
		[itemViews removeObjectsInArray: archivableSubviews];
		return archivableSubviews;
	}
		
	return object;
}

- (void) encodeWithCoder: (NSCoder *)coder
{
	if ([coder allowsKeyedCoding] == NO)
	{	
		[NSException raise: NSInvalidArgumentException format: @"ETView only "
			@"supports keyed archiving"];
	}

	/* We must disable the encoding of item subviews by catching it on 
	   -[ETView encodeWithCoder:] with call back -archiver:willEncodeObject: */
	[(NSKeyedArchiver *)coder setDelegate: self];
	[super encodeWithCoder: coder];

	// TODO: We might want to use -encodeLateBoundObject:forKey: to serialize 
	// an id rather the object itself
	[coder encodeObject: [self titleBarView] forKey: @"ETTitleBarView"];
	[coder encodeObject: [self wrappedView] forKey: @"ETWrappedView"];	
	[coder encodeObject: [self temporaryView] forKey: @"ETTemporaryView"];
	[coder encodeBool: [self isDisclosable] forKey: @"ETDisclosable"];
	[coder encodeBool: [self usesCustomTitleBar] forKey: @"ETUsesCustomTitleBar"];
	[coder encodeBool: [self isFlipped] forKey: @"ETFlipped"];

	[(NSKeyedArchiver *)coder setDelegate: nil];
}

- (id) initWithCoder: (NSCoder *)coder
{
	self = [super initWithCoder: coder];
	
	if ([coder allowsKeyedCoding] == NO)
	{	
		[NSException raise: NSInvalidArgumentException format: @"ETView only "
			@"supports keyed unarchiving"];
		return nil;
	}
	
	// NOTE: Don't use accessors, they involve a lot of set up logic and they
	// would change the subviews in relation with their call order.
	_usesCustomTitleBar = [coder decodeBoolForKey: @"ETUsesCustomTitleBar"];	
	_disclosable = [coder decodeBoolForKey: @"ETDisclosable"];
	ASSIGN(_titleBarView, [coder decodeObjectForKey: @"ETTitleBarView"]);
	ASSIGN(_wrappedView, [coder decodeObjectForKey: @"ETWrappedView"]);
	ASSIGN(_temporaryView, [coder decodeObjectForKey: @"ETTemporaryView"]);
	[self setFlipped: [coder decodeBoolForKey: @"ETFlipped"]];

	return self;
}


Old Ideas
---------

## Layout

For ETFlow/Line/ColumnLayout, my idea was to introduce layout strategie as a ETLayoutAlgorithm class tree:
	- ETHorizontalFlowAlgorithm
	- ETVerticalFlowAlgorithm
For these two subclasses, you can specify how the overflow should be handled. In ETFlowLayout, the right Flow algorithm is selected depending on the value returned by -isVerticallyOriented. In a very-long term vision, these classes could be eventually be subclassed for implementing text layout algorithms (see Universal Polygons in STEPS first year report).
So ETLineLayout results of using ETHorizontalFlowAlgorithm limited to a single line and the overflow hidden. Similarly ETColumnLayout results of using ETVerticalFlowAlgorithm limited to a single column and the overflow hidden.

* Fix stack and unstack operations, they are currently broken. Documentation is probably missing in this area. Stack/Unstack operations are unrelated to the stack layout (we got a naming issue here), they allow to set a temporary layout on an item group, so that the child item becomes visible instead of the drawing or the view of the item group itself. For example, you set a table layout on a folder item, then the content of the folder appears 'exploded' as a table view rather than just an opaque folder icon. This feature gives a very generic implementation of Aperture-like stacks.