//
//  EXPElement.m
//  XMLTest
//
//  Created by Ashley on 11/04/2007.
//  Copyright 2007 __MyCompanyName__. All rights reserved.
//

#import "EXPElement.h"
#import "EXPSheet.h"

int nextIdentifier = 0;

int _numElementsInited = 0;
int _numElementsDealloced = 0;

// @class EXPParameterElement;

@implementation EXPElement

- (id) init
{
	self = [super init];
	
//	[self setName:@""];
	_identifier = nextIdentifier++;
	
	_expressionList = [[EXPExpressionList alloc] init];
	_expression = nil;
	
	_sheet = nil;
	_name = nil;
	_address = 0;
	_isPrivate = NO;
	
	_inputs = [[NSMutableArray alloc] init];
	_outputs = [[NSMutableArray alloc] init];
	
	_numElementsInited++;

	return self;
}

- (void) setElementFromXLMElement:(NSXMLElement *)element
{
	NSXMLNode *node = [element attributeForName:@"name"];
	if (node!=nil) {
		NSString *name = [node stringValue];
		[self setName:name];
	}
	
/*	NSArray *elements = [element elementsForName:@"expression"];
	if ([elements count]!=0) {
		NSXMLElement *expression = [elements objectAtIndex:0];
		NSXMLNode *child = [expression childAtIndex:0];
		do {
			NSString *name = [child name];
			NSString *value = [[child stringValue] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
			NSDictionary *dict = [[NSDictionary alloc] initWithObjectsAndKeys:name, @"name", value, @"value", nil];
			[[self expressionList] addObject:dict];
			[dict release];
		} while ( child = [child nextSibling] );
	} */
	[[self expressionList] setExpressionListFromXMLElement:element];

}

- (void) writeElementToXMLElement:(NSXMLElement *)element
{
	return;
}

- (BOOL) setElementFromParser:(EXPParser *)parser symbolTable:(EXPSymbolTable *)symbolTable inputs:(id)inputs
{
	NSString *identifier = [[NSString alloc] initWithString:[parser symbol]];
	[parser readSymbol];
	[self setName:identifier];
			
	if (![parser checkSymbol:@"="]) {
		[identifier release];
		return NO;
	}
			
//	[parser readSymbol];
	EXPExpressionList *expressionList = [self expressionList];
	[expressionList setExpressionListFromParser:parser symbolTable:symbolTable inputs:inputs];

	[identifier release];

	return YES;
}

- (void) processExpressionList
{
	printf("processExpressionList: %s\n", [[self name] UTF8String]);
	NSMutableArray *expressionList = [self expressionList];
	NSMutableArray *inputs = [self inputs];
	
	int i;
	for (i=0; i<[expressionList count]; i++) {
		NSDictionary *dict = [expressionList objectAtIndex:i];
		NSString *name = [dict objectForKey:@"name"];
		NSString *value = [dict objectForKey:@"value"];
		
		EXPElement *element = nil;
		
		if (([name isEqualToString:@"state"]) || ([name isEqualToString:@"auxiliary"]) || ([name isEqualToString:@"parameter"])) {
			BOOL found = NO;
			int j;
			for(j=0; j<[inputs count]; j++) {
				element = [inputs objectAtIndex:j];
				if ([value isEqualToString:[element name]]) {
					found = YES;
					break;
				}
			}
			
			if (!found) {
				printf("Cannot find element '%s' in input list of element '%s'\n", [value UTF8String], [[self name] UTF8String]);
			}
			
			NSDictionary *newDict = [[NSDictionary alloc] initWithObjectsAndKeys:name, @"name", element, @"value", nil];
			[expressionList replaceObjectAtIndex:i withObject:newDict];
			[newDict release];
			
		} // else if ([name isEqualToString:@"operator"]) {
//		} else if ([name isEqualToString:@"bracket"]) {
//		} else if ([name isEqualToString:@"literal"]) {
//		} 
		
	}
}

- (void) generateParseTree
{
	EXPExpressionList *list = [self expressionList];
	
	EXPExpression *exp = [list generateParseTreeForElement:self];
	[self setExpression:exp];
//	printf("\nTree generated for '%s'\n", [[self name] UTF8String]);
//	[exp dump];
	[exp release];
	
}

- (id) expression
{
	return _expression;
}

- (void) setExpression:(EXPExpression *)expression
{
	[expression retain];
	[_expression release];
	_expression = expression;
}

- (id) expressionList
{
	return _expressionList;
}

- (void) setExpressionList:(id)expressionList
{
	[expressionList retain];
	[_expressionList release];
	_expressionList = expressionList;
}

- (void) setName:(NSString *)name
{
	[name retain];
	[_name release];
	_name = name;
}

- (NSString *)name
{
	return _name;
}

- (void) setLabel:(id)label
{
	[label retain];
	[_label release];
	_label = label;
}

- (id) label
{
	return _label;
}

- (void) setSheet:(id)sheet
{
//	[sheet retain];
//	[_sheet release];
	_sheet = sheet;
}

- (id) sheet
{
	return _sheet;
}

- (id) inputs
{
	return _inputs;
}

- (void) setInputs:(id)inputs
{
	[inputs retain];
	[_inputs release];
	_inputs = inputs;
}

- (void) addInput:(id)input
{
	[[self inputs] addObject:input];
}

- (id) outputs
{
	return _outputs;
}

- (void) setOutputs:(id)outputs
{
	[outputs retain];
	[_outputs release];
	_outputs = outputs;
}

- (void) addOutput:(id)output
{
	[[self outputs] addObject:output];
}

- (void) setAddress:(unsigned int)address
{
//	printf("Setting address for %s %s to %04x\n", [[[self class] description] UTF8String], [[self name] UTF8String], address);
	_address = address;
}

- (unsigned int) address
{
	return _address;
}

- (unsigned int) length
{
	return 1;
}

- (void) setIsPrivate:(BOOL)isPrivate
{
	_isPrivate = isPrivate;
}

- (BOOL) isPrivate
{
	return _isPrivate;
}

- (double) value
{
	EXPExpression *exp = [self expression];
	if (exp==nil) {
		return 0.0;
	}
	
	double x = [exp result];
	return x;
}

- (void) handleError:(NSError *)err
{
	[[[self sheet] model] handleError:err];
}

- (NSString *)elementType
{
	return @"none";
}

//	Move to Parameter...
- (BOOL) dependsUpon:(EXPElement *)target
{
	NSArray *inputs = [self inputs];
	if ([inputs containsObject:target]) {
		return YES;
	}
	
	int i;
	for(i=0; i<[inputs count]; i++) {
		EXPElement *input = [inputs objectAtIndex:i];
//		if (([input isAuxiliary]) && ([input dependsUpon:target])) {
		if (([[input elementType] isEqualToString:@"auxiliary"]) && ([input dependsUpon:target])) {
			return YES;
		}
	}
	
	return NO;
}

- (NSComparisonResult) compareElements:(EXPElement *)comparator
{
	NSComparisonResult result;
	if ([self dependsUpon:comparator]) {
		result = NSOrderedAscending;
	} else if ([comparator dependsUpon:self]) {
		result = NSOrderedDescending;
	} else {
		result = NSOrderedSame;
	}
	
	return result;
}

- (void) clear
{
	[self setExpression:nil];
	[self setExpressionList:nil];
	[self setInputs:nil];
	[self setOutputs:nil];
}

- (void) dump
{
	printf("%s retain count = %d\n", [[self description] UTF8String], [self retainCount]);
	[[self expression] dump];
	[[self expressionList] dump];
	
	NSArray *inputs = [self inputs];
	int i;
	for(i=0; i<[inputs count]; i++) {
		[[inputs objectAtIndex:i] dump];
	}
	
	NSArray *outputs = [self outputs];
	for(i=0; i<[outputs count]; i++) {
		[[outputs objectAtIndex:i] dump];
	}
}

- (NSString *)description
{
	return [NSString stringWithFormat:@"EXPElement '%@'", [self name]];
}

- (id)copyWithZone:(NSZone *)zone
{
	EXPElement *doppel = [[[self class] allocWithZone:zone] init];
	
	[doppel setName:[self name]];
	[doppel setSheet:[self sheet]];
	[[[doppel expressionList] list] addObjectsFromArray:[[self expressionList] list]];
	[doppel setExpression:[self expression]];
	[doppel setInputs:[self inputs]];
	[doppel setOutputs:[self outputs]];
	
	return doppel;
}

/*- (id) retain
{
	printf("Retaining element %s retainCount = %d\n", [[self name] UTF8String], [self retainCount]);
	return [super retain];
}

- (void) release
{
	printf("Releasing element %s retainCount = %d\n", [[self name] UTF8String], [self retainCount]);
	[super release];
} */

+ (void) reportElementCount
{
	printf("Elements inited =    %d\n", _numElementsInited);
	printf("Elements dealloced = %d\n", _numElementsDealloced);
}

- (BOOL) compileInitialisation:(EXPStackMachine *)machine error:(NSError **)err opcode:(unsigned int)opcode
{
	EXPExpression *exp = [self expression];
	BOOL success = [exp compile:machine error:err];
	if (!success) {
		return NO;
	}
	[machine putUInt:opcode];
	[machine putUInt:[self address]];
	
	return YES;
}

- (BOOL) compile:(EXPStackMachine *)machine error:(NSError **)err opcode:(unsigned int)opcode
{
	[machine putUInt:opcode];
	[machine putUInt:[self address]];
	return YES;
}

- (BOOL) compile:(EXPStackMachine *)machine error:(NSError **)err withArguments:(NSArray *)arguments
{
	EXPExpression *exp = [self expression];
	BOOL success = [exp compile:machine error:err];
	return success;
}

- (void) dealloc
{
//	printf("EXPElement - (void) dealloc '%s'\n", [_name UTF8String]);
	_numElementsDealloced++;
	[_name release];
	[_label release];
	[_expressionList release];
	[_expression release];
	[_inputs release];
	[_outputs release];
	[super dealloc];
}

@end
