/*************************************************************************
 * Copyright (c) 2011 AT&T Intellectual Property 
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors: Details at http://www.graphviz.org/
 *************************************************************************/

#import "GVAttributeInspectorController.h"
#import "GVAttributeSchema.h"
#import "GVDocument.h"
#import "GVZGraph.h"
#import "GVWindowController.h"

@implementation GVAttributeInspectorController

- (id)init
{
	if (self = [super initWithWindowNibName: @"Attributes"]) {
		_allSchemas = nil;
		_allAttributes = [[NSMutableDictionary alloc] init];
		_inspectedDocument = nil;
		_otherChangedGraph = YES;
	}
	return self;
}

- (void)awakeFromNib
{
	/* set component toolbar */
	[_allSchemas release];
	_allSchemas = [[NSDictionary alloc] initWithObjectsAndKeys:
		[GVAttributeSchema attributeSchemasWithComponent:@"graph"], [graphToolbarItem itemIdentifier],
		[GVAttributeSchema attributeSchemasWithComponent:@"node"], [nodeDefaultToolbarItem itemIdentifier],
		[GVAttributeSchema attributeSchemasWithComponent:@"edge"], [edgeDefaultToolbarItem itemIdentifier],
		nil];
	[componentToolbar setSelectedItemIdentifier:[graphToolbarItem itemIdentifier]];
	[self toolbarItemDidSelect:nil];
		
	/* start observing whenever a window becomes main */
	[self graphWindowDidBecomeMain:nil];
	[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(graphWindowDidBecomeMain:) name:NSWindowDidBecomeMainNotification object:nil];
}

- (IBAction)toolbarItemDidSelect:(id)sender
{
	/* reload the table */
	[attributeTable reloadData];
}

- (void)graphWindowDidBecomeMain:(NSNotification *)notification
{
	NSWindow* mainWindow = notification ? [notification object] : [NSApp mainWindow];
	GVDocument* mainWindowDocument = [[mainWindow windowController] document];
		
	/* update and observe referenced document */
			NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter];
	if (_inspectedDocument)
		[defaultCenter removeObserver:self name:@"GVGraphDocumentDidChange" object:_inspectedDocument];
	_inspectedDocument = mainWindowDocument;
	[defaultCenter addObserver:self selector:@selector(graphDocumentDidChange:) name:@"GVGraphDocumentDidChange" object:mainWindowDocument];

	[self reloadAttributes];
		
			/* update the UI */
			[[self window] setTitle:[NSString stringWithFormat:@"%@ Attributes", [mainWindow title]]];
			[attributeTable reloadData];
}

- (void)graphDocumentDidChange:(NSNotification *)notification
{
	/* if we didn't instigate the change, update the UI */
	if (_otherChangedGraph) {
		[self reloadAttributes];
		[attributeTable reloadData];
	}
}

- (void)reloadAttributes
{
	/* reload the attributes from the inspected document's graph */
	[_allAttributes removeAllObjects];
	if ([_inspectedDocument respondsToSelector:@selector(graph)]) {
		GVZGraph *graph = [_inspectedDocument graph];
		[_allAttributes setObject:graph.graphAttributes forKey:[graphToolbarItem itemIdentifier]];
		[_allAttributes setObject:graph.defaultNodeAttributes forKey:[nodeDefaultToolbarItem itemIdentifier]];
		[_allAttributes setObject:graph.defaultEdgeAttributes forKey:[edgeDefaultToolbarItem itemIdentifier]];
	}
}

- (NSArray *)toolbarSelectableItemIdentifiers:(NSToolbar *)toolbar
{
	/* which toolbar items are selectable */
	return [NSArray arrayWithObjects:
		[graphToolbarItem itemIdentifier],
		[nodeDefaultToolbarItem itemIdentifier],
		[edgeDefaultToolbarItem itemIdentifier],
		nil];
}

- (NSCell *)tableView:(NSTableView *)tableView dataCellForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
{
	if ([[tableColumn identifier] isEqualToString:@"value"]) {
		/* use the row's schema's cell */
		NSCell *cell = [[[_allSchemas objectForKey:[componentToolbar selectedItemIdentifier]] objectAtIndex:row] cell];
		[cell setEnabled:[_allAttributes count] > 0];
		return cell;
	}
	else
		/* use the default cell (usually a text field) for other columns */
		return nil;
}

- (void)tableViewSelectionDidChange:(NSNotification *)aNotification
{
	NSInteger selectedRow = [[aNotification object] selectedRow];
	NSString* documentation = selectedRow == -1 ? nil : [[[_allSchemas objectForKey:[componentToolbar selectedItemIdentifier]] objectAtIndex: selectedRow] documentation];
	[[documentationWeb mainFrame] loadHTMLString:documentation baseURL:[NSURL URLWithString:@"http://www.graphviz.org/"]];
}

- (NSInteger)numberOfRowsInTableView:(NSTableView *)aTableView
{
	return [[_allSchemas objectForKey:[componentToolbar selectedItemIdentifier]] count];
}

- (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)rowIndex
{
	NSString *selectedComponentIdentifier = [componentToolbar selectedItemIdentifier];
	NSString *attributeName = [[[_allSchemas objectForKey:selectedComponentIdentifier] objectAtIndex:rowIndex] name];
	if ([[tableColumn identifier] isEqualToString:@"key"])
		return attributeName;
	else if ([[tableColumn identifier] isEqualToString:@"value"])
		/* return the inspected graph's attribute value, if any */
		return [[_allAttributes objectForKey:selectedComponentIdentifier] valueForKey:attributeName];
	else
		return nil;
}

- (void)tableView:(NSTableView *)aTableView setObjectValue:(id)anObject forTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)rowIndex
{
	if ([[tableColumn identifier] isEqualToString:@"value"])
		{
			NSString *selectedComponentIdentifier = [componentToolbar selectedItemIdentifier];
			NSString *attributeName = [[[_allSchemas objectForKey:selectedComponentIdentifier] objectAtIndex:rowIndex] name];
			
			/* set or remove the key-value on the selected attributes */
			/* NOTE: to avoid needlessly reloading the table in graphDocumentDidChange:, we fence this change with _otherChangedGraph = NO */
			_otherChangedGraph = NO;
			@try {
				[[_allAttributes objectForKey:selectedComponentIdentifier] setValue:anObject forKey:attributeName];
			}
			@finally {
				_otherChangedGraph = YES;
			}
		}

}


- (void)dealloc
{
	[[NSNotificationCenter defaultCenter] removeObserver:self name:NSWindowDidBecomeMainNotification object:nil];
	[_allSchemas release];
	[_allAttributes release];
	[super dealloc];
}

@end
