//
//  EXPExpressionList.m
//  XMLTest
//
//  Created by Ashley on 16/04/2007.
//  Copyright 2007 __MyCompanyName__. All rights reserved.
//

#import "EXPExpressionList.h"
#import "EXPElement.h"
#import "EXPParser.h"
#import "EXPSymbolTable.h"
#import "EXPExpression.h"

NSArray *_EXPExpressionList_opList = nil;

@implementation EXPExpressionList

+ (NSArray *) opList
{
	if (_EXPExpressionList_opList==nil) {
		_EXPExpressionList_opList = [NSArray arrayWithObjects:
			@"+", @"-", @"*", @"/", @"^", 
			@"==", @"<>", @">", @">=", @"<", @"<=", @"&&", @"||", @"?", @":",
			nil];
	}
	
	return _EXPExpressionList_opList;
}

- (id) init
{
	self = [super init];
	_list = [[NSMutableArray alloc] init];
	_symbol = nil;
	return self;
}

- (id) list
{
	return _list;
}

- (void) addObject:(id)object
{
	[[self list] addObject:object];
}

- (void) addName:(NSString *)name andValue:(id)value
{
	NSDictionary *dict = [[NSDictionary alloc] initWithObjectsAndKeys:name, @"name", value, @"value", nil];
	[self addObject:dict];
	[dict release];
}

- (void) setExpressionListFromXMLElement:(NSXMLElement *)element
{
	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]];
			[self addName:name andValue:value];
		} while ( child = [child nextSibling] );
	}

}

- (BOOL) addFactorFromParser:(EXPParser *)parser symbolTable:(EXPSymbolTable *)symbolTable inputs:(id)inputs
{
	NSString *name;
	
//	[parser readSymbol];
	if ([[parser symbol] isEqualToString:@"("]) {
		[self addName:@"bracket" andValue:@"("];
		[parser readSymbol];
		[self setExpressionListFromParser:parser symbolTable:symbolTable inputs:inputs];
		 
		if ([parser testSymbol:@")"]) {
			[self addName:@"bracket" andValue:@")"];
		} else {
			return NO;
		}
	} else if ([parser isLiteral]) {
		name = [[NSString alloc] initWithString:[parser symbol]];
		[parser readSymbol];
//		printf("Got literal %g\n", [name doubleValue]);
		[self addName:@"literal" andValue:name];
//		[name release];
		
	} else if ([parser isIdentifier]) {
		name = [[NSString alloc] initWithString:[parser symbol]];
		[parser readSymbol];
//		printf("Got symbol %s\n", [name UTF8String]);
		
		EXPElement *element = [symbolTable symbolForName:name];
		if (element==nil) {
			[name release];
			return NO;
		}
		
		if (![inputs containsObject:element]) {
			[inputs addObject:element];
		}
		
		NSString *value = [element elementType];
		[self addName:value andValue:element];

// Function call or delayed variable?
		if ([parser testSymbol:@"("]) {
			[self addName:@"bracket" andValue:@"("];
			for (;;) {
				[self setExpressionListFromParser:parser symbolTable:symbolTable inputs:inputs];
				if ([parser testSymbol:@","]) {
					[self addName:@"comma" andValue:@","];
				} else {
					break;
				}
			}
		 
			if ([parser testSymbol:@")"]) {
				[self addName:@"bracket" andValue:@")"];
			} else {
				[name release];
				return NO;
			}
		}
		
		[name release];
				
	} else if ([[parser symbol] isEqualToString:@"-"]) {
		[self addName:@"operator" andValue:@"-"];
		[parser readSymbol];
		[self addFactorFromParser:parser symbolTable:symbolTable inputs:inputs];
	}

	return YES;
}

- (BOOL) setExpressionListFromParser:(EXPParser *)parser symbolTable:(EXPSymbolTable *)symbolTable inputs:(id)inputs
{
	BOOL success = YES;

	for(;;) {
		success = [self addFactorFromParser:parser symbolTable:symbolTable inputs:inputs];
		
		if (!success) {
			break;
		}
		
		if (![parser isBinaryOp]) {
			break;
		}
				
		NSString *name = [[NSString alloc] initWithString:[parser symbol]];
		[parser readSymbol];
		[self addName:@"operator" andValue:name];
		[name release];
			
	}

	return success;
}

- (void) process:(EXPElement *)element
{
	NSMutableArray *inputs = [element inputs];
	NSMutableArray *list = [self list];
	
	int i;
	for (i=0; i<[list count]; i++) {
		NSDictionary *dict = [list 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], [[element name] UTF8String]);
			}
			
			NSDictionary *newDict = [[NSDictionary alloc] initWithObjectsAndKeys:name, @"name", element, @"value", nil];
			[list replaceObjectAtIndex:i withObject:newDict];
			[newDict release];
			
		}
	}
}

- (EXPExpression *) generateParseTreeForElement:(EXPElement *)element
{
/*	EXPSymbolTable *symbolTable = [[EXPSymbolTable alloc] init];
	
	NSArray *inputs = [element inputs];
	int i;
	for(i=0; i<[inputs count]; i++) {
		EXPElement *element = [inputs objectAtIndex:i];
		[symbolTable declareSymbol:element];
	}
	[symbolTable dump]; */
	
	EXPExpression *exp = [EXPExpression expression:self];
	
//	[symbolTable release];
	return exp;
}

- (void) reset
{
	_counter = 0;
	[self setSymbol:nil];
}

- (void) skipspace
{
}

- (void) setSymbol:(NSDictionary *)symbol
{
	[symbol retain];
	[_symbol release];
	_symbol = symbol;
}

- (NSMutableString *) symbol
{
	return [_symbol objectForKey:@"value"];
}

- (void) readSymbol;
{
	NSArray *list = [self list];
	
	if (_counter<[list count]) {
//		[self setSymbol:[list objectAtIndex:_counter++]];
		_symbol = [list objectAtIndex:_counter++];
	} else {
//		[self setSymbol:nil];
		_symbol = nil;
	}
}

- (BOOL) testSymbol:(NSString *)symbol;
{
	int oldCounter = _counter;
	
	[self readSymbol];
	
//	NSString *name;
	id sym = [self symbol];
	if ([sym isKindOfClass:[EXPElement class]]) {
		sym = [sym name];
	}
	if ([sym isEqualToString:symbol]) {
		return YES;
	}
	_counter = oldCounter;
	
	return NO;
}

- (BOOL) isLiteral;
{
/*	NSArray *list = [self list];
	if (_counter>=[list count]) {
		return NO;
	}
	
	NSDictionary *dict = [list objectAtIndex:_counter]; */
	
	NSDictionary *dict = _symbol;
	
	return [[dict objectForKey:@"name"] isEqualToString:@"literal"];
	
}

- (BOOL) isIdentifier;
{
/*	NSArray *list = [self list];
	if ((_counter>[list count]) || ()) {
		return NO;
	} */

	NSDictionary *dict = _symbol;
	
	NSString *type = [dict objectForKey:@"name"];
	return [type isEqualToString:@"variable"] || [type isEqualToString:@"auxiliary"] || [type isEqualToString:@"parameter"] || 
		   [type isEqualToString:@"function"] || [type isEqualToString:@"table"];
	
}

- (BOOL) isEndOfLine
{
	return NO;
}

- (BOOL) isEndOfFile
{
	return NO;
}

- (NSString *)description
{
	return [[self list] description];
}

- (void) dump;
{
	printf("Expression List\n");

	NSArray *list = [self list];
	
	int i;
	for(i=0; i<[list count]; i++) {
		NSDictionary *dict = [list objectAtIndex:i];
		printf("\tname = %s value = %s\n", [[dict objectForKey:@"name"] UTF8String], [[[dict objectForKey:@"value"] description] UTF8String]);
	}
}

- (void) dealloc
{	
//	printf("EXPExpressionList - (void) dealloc\n");
	[_list release];
	[_symbol release];
	[super dealloc];
}

@end
