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

#import "EXPSheet.h"
#import "EXPModel.h"
#import "EXPFunctionElement.h"
#import "EXPPrintElement.h"
#import "EXPPlotElement.h"
#import "EXPSwitchElement.h"
#import "EXPTableElement.h"
#import "EXPDimensionElement.h"

@implementation EXPSheet

- (id) init
{
	self = [super init];
	_name = nil;
//	_elements = [[NSMutableArray alloc] init];
	_symbolTable = [[EXPSymbolTable alloc] init];
	return self;
}

- (BOOL) addElementsFromXMLElement:(NSXMLElement *)sheetElement 
{
	NSString *sheetName = [[sheetElement attributeForName:@"name"] stringValue];
	[self setName:sheetName];
	[sheetName release];

	NSArray *elements = [sheetElement elementsForName:@"element"];
		
	NSMutableDictionary *elementTable = [[NSMutableDictionary alloc] init];
	NSMutableArray *connectors = [[NSMutableArray alloc] init];
	NSMutableArray *auxiliaries = [[NSMutableArray alloc] init];
	NSMutableArray *variables = [[NSMutableArray alloc] init];
	NSMutableArray *parameters = [[NSMutableArray alloc] init];
	NSMutableArray *flows = [[NSMutableArray alloc] init];
	
	int i;
	for (i=0; i<[elements count]; i++) {
		NSXMLElement *element = [elements objectAtIndex:i];
		NSString *name = [[element attributeForName:@"name"] stringValue];
		NSString *type = [[element attributeForName:@"type"] stringValue];
		if (name!=nil) {
			printf("Name = %-20s Type = %-20s\n", [name UTF8String], [type UTF8String]);
		}
			
		if ([elementTable objectForKey:name]!=nil) {
			printf("Multiply declared symbol%s\n", [name UTF8String]);
		}
			
		if ([type isEqualToString:@"parameter"]) {
			EXPParameterElement *param = [[EXPParameterElement alloc] init];
			[param setElementFromXLMElement:element];
			[param setSheet:self];
			[elementTable setObject:param forKey:name];
			[parameters addObject:param];
			[param release];
//		|| ([type isEqualToString:@"state"]) || ([type isEqualToString:@"flow"]) || ([type isEqualToString:@"auxiliary"])
		} else if ([type isEqualToString:@"state"]) {
			EXPStateElement *state = [[EXPStateElement alloc] init];
			[state setElementFromXLMElement:element];
			[state setSheet:self];
			[elementTable setObject:state forKey:name];
			[variables addObject:state];
			[state release];
		} else if ([type isEqualToString:@"flow"]) {
			EXPFlowElement *flow = [[EXPFlowElement alloc] init];
			[flow setElementFromXLMElement:element];
			[flow setSheet:self];
			[elementTable setObject:flow forKey:name];
			[flows addObject:flow];
			[flow release];
		} else if ([type isEqualToString:@"auxiliary"]) {
			EXPAuxiliaryElement *aux = [[EXPAuxiliaryElement alloc] init];
			[aux setElementFromXLMElement:element];
			[aux setSheet:self];
			[elementTable setObject:aux forKey:name];
			[auxiliaries addObject:aux];
			[aux release];
		} else if ([type isEqualToString:@"connector"]) {
			EXPConnectorElement *connector = [[EXPConnectorElement alloc] init];
			[connector setElementFromXLMElement:element];
			[connectors addObject:connector];
			[connector release];
		} else {
			printf("Cannot decide on type for symbol%s\n", [name UTF8String]);
		}
	}
		
	for (i=0; i<[connectors count]; i++) {
		EXPConnectorElement *connector = [connectors objectAtIndex:i];
		
		NSString *inputName = [connector input];
		EXPElement *inputElement = [elementTable objectForKey:inputName];
		if (inputElement==nil) {
			printf("Cannot find element %s\n", [inputName UTF8String]);
		}
		[connector setInput:inputElement];
		
		NSString *outputName = [connector output];
		EXPElement *outputElement = [elementTable objectForKey:outputName];
		if (outputElement==nil) {
			printf("Cannot find element %s\n", [outputName UTF8String]);
		}
		[connector setOutput:outputElement];
		
		[inputElement addOutput:outputElement];
		[outputElement addInput:inputElement];
		
	}
	
	for (i=0; i<[flows count]; i++) {
		EXPFlowElement *flow = [flows objectAtIndex:i];
		
		NSString *sourceName = [flow source];
		EXPStateElement *sourceElement = [elementTable objectForKey:sourceName];
		if ((sourceElement==nil) && (sourceName!=nil)) {
			printf("Cannot find element %s\n", [sourceName UTF8String]);
		}
		[flow setSource:sourceElement];
		[sourceElement addOutflow:flow];

		NSString *destinationName = [flow destination];
		EXPStateElement *destinationElement = [elementTable objectForKey:destinationName];
		if ((destinationElement==nil) && (destinationName!=nil)) {
			printf("Cannot find element %s\n", [destinationName UTF8String]);
		}
		[flow setDestination:destinationElement];
		[destinationElement addInflow:flow];

	}
	
	EXPElement *element = nil;
	NSEnumerator *enumerator = [elementTable objectEnumerator];
	
	while ((element = [enumerator nextObject])) {
		printf("processExpressionList: %s\n", [[element name] UTF8String]);
		[[element expressionList] process:element];
	}
	
//	[self setElements:elementTable];
	[self setAuxiliaries:auxiliaries];
	[self setVariables:variables];
	[self setParameters:parameters];
	[self setConnectors:connectors];
	[self setFlows:flows];
	
	[elementTable release];
	[auxiliaries release];
	[variables release];
	[parameters release];
	[connectors release];
	[flows release];
	
	return YES;
}

/*- (BOOL) processOption:(EXPParser *)parser model:(id)model
{
	NSString *optionName = [[NSString alloc] initWithString:[parser symbol]];
	[parser readSymbol];

	if(![parser testSymbol:@"="]) {
		[optionName release];
		return NO;
	}

	if (!([parser isLiteral] || [parser isStringLiteral])) {
		return NO;
	}

	BOOL success = YES;
	if ([optionName isEqualToString:@"tstart"]) {
		[model setT0:[[parser symbol] floatValue]];
	} else if ([optionName isEqualToString:@"tstop"]) {
		[model setT1:[[parser symbol] floatValue]];
	} else if ([optionName isEqualToString:@"outstep"]) {
		[model setOutputStep:[[parser symbol] floatValue]];
	} else if ([optionName isEqualToString:@"tstep"]) {
		[model setDt:[[parser symbol] floatValue]];
	} else if ([optionName isEqualToString:@"epsilon"]) {
		[model setEps:[[parser symbol] floatValue]];
	} else if ([optionName isEqualToString:@"device"]) {
		NSString *device = [[NSString alloc] initWithString:[parser symbol]];
		[model setGraphicsDevice:device];
		[device release];
	} else if ([optionName isEqualToString:@"plotfile"]) {
		NSString *plotfile = [[NSString alloc] initWithString:[parser symbol]];
		[model setGraphicsFile:plotfile];
		[plotfile release];
	} else {
		success = NO;
	}
	
	[parser readSymbol];
	[optionName release];
	
	return success;
} */

//- (BOOL) loadFromDDEData:(NSData *)data encoding:(NSStringEncoding)encoding
- (BOOL) loadFromParser:(EXPParser *)parser /*encoding:(NSStringEncoding)encoding*/
{
	BOOL success = YES;

//	NSString *ddeString = [[NSString alloc] initWithData:data encoding:encoding];
//	printf("%s\n", [ddeString UTF8String]);
	
	EXPSymbolTable *symbolTable = [[EXPSymbolTable alloc] init];
	[EXPFunctionElement registerDefaultFunctions:symbolTable];
	
//	NSMutableDictionary *elementTable = [[NSMutableDictionary alloc] init];
	NSMutableArray *auxiliaries = [[NSMutableArray alloc] init];
	NSMutableArray *variables = [[NSMutableArray alloc] init];
	NSMutableArray *parameters = [[NSMutableArray alloc] init];
	NSMutableArray *flows = [[NSMutableArray alloc] init];
	NSMutableArray *switches = [[NSMutableArray alloc] init];
	NSMutableArray *tables = [[NSMutableArray alloc] init];
	NSMutableArray *dimensions = [[NSMutableArray alloc] init];
	NSMutableArray *printers = [[NSMutableArray alloc] init];
	NSMutableArray *plotters = [[NSMutableArray alloc] init];
	
	int nextSwitchNumber = 0;

//	EXPParser *parser = [[EXPParser alloc] init];
//	[parser setString:ddeString];
//	[ddeString release];
		
	 while (![parser isEndOfFile]) {
		if ([parser testSymbol:@"dim"]) {
			do {
				EXPDimensionElement *dim = [[EXPDimensionElement alloc] init];
				[dim setSheet:self];
				success = [dim setElementFromParser:parser symbolTable:symbolTable inputs:nil];
				if (!success) {
					[dim release];
					break;
				}
				[symbolTable declareSymbol:dim];
				[dimensions addObject:dim];
				[dim release];
				
			} while ([parser testSymbol:@","]);
			
			if (!success) {
				break;
			}
			
			if (!([parser isEndOfLine] || [parser testSymbol:@";"])) {
				success = NO;
				break;
			}

		} else if ([parser testSymbol:@"param"]) {
			do {
				NSMutableArray *inputs = [[NSMutableArray alloc] init];
				EXPParameterElement *param = [[EXPParameterElement alloc] init];
				[param setSheet:self];
				success = [param setElementFromParser:parser symbolTable:symbolTable inputs:inputs];
//				[elementTable setObject:param forKey:[param name]];
				[symbolTable declareSymbol:param];
				[parameters addObject:param];
				[param setInputs:inputs];
				[param release];
				[inputs release];
				
			} while ([parser testSymbol:@","]);
			
			if (!success) {
				break;
			}
			
			if (!([parser isEndOfLine] || [parser testSymbol:@";"])) {
				success = NO;
				break;
			}

		} else if ([parser testSymbol:@"var"]) {
			do {
				NSMutableArray *inputs = [[NSMutableArray alloc] init];
				EXPStateElement *state = [[EXPStateElement alloc] init];
				[state setSheet:self];
				success = [state setElementFromParser:parser symbolTable:symbolTable inputs:inputs];
//				[elementTable setObject:state forKey:[state name]];
				[symbolTable declareSymbol:state];
				[state setInputs:inputs];
				[variables addObject:state];
				[state release];
				[inputs release];
				
			} while ([parser testSymbol:@","]);
			
			if (!success) {
				break;
			}
			
			if (!([parser isEndOfLine] || [parser testSymbol:@";"])) {
				success = NO;
				break;
			}

		} else if ([parser testSymbol:@"aux"]) {
			do {
				EXPAuxiliaryElement *aux = [[EXPAuxiliaryElement alloc] init];
				[aux setSheet:self];
				NSString *name = [[NSString alloc] initWithString:[parser symbol]];				
				[parser readSymbol];
				[aux setName:name];
				[name release];
//				[elementTable setObject:aux forKey:[aux name]];
				[symbolTable declareSymbol:aux];
				[auxiliaries addObject:aux];
				[aux release];
				
			} while ([parser testSymbol:@","]);
			
			if (!([parser isEndOfLine] || [parser testSymbol:@";"])) {
				success = NO;
				break;
			}

		} else if ([parser testSymbol:@"table"]) {
			EXPTableElement *table = [[EXPTableElement alloc] init];
			[table setSheet:self];
			NSMutableArray *inputs = [[NSMutableArray alloc] init];
			success = [table setElementFromParser:parser symbolTable:symbolTable inputs:inputs];
//			[elementTable setObject:table forKey:[table name]];
			[symbolTable declareSymbol:table];
			[tables addObject:table];
			[inputs release];
			[table release];

		} else if ([parser testSymbol:@"on"]) {
			EXPSwitchElement *switchElement = [[EXPSwitchElement alloc] init];
//			[switchElement setModel:[self model]];
			NSString *name = [[NSString alloc] initWithFormat:@"Switch %d", nextSwitchNumber];
			[switchElement setName:name];
			[name release];
			
			EXPExpressionList *expressionList = [[EXPExpressionList alloc] init];
			success = [expressionList setExpressionListFromParser:parser symbolTable:symbolTable inputs:nil];
			[switchElement setExpressionList:expressionList];
			[expressionList release];
			
			if (![parser testSymbol:@"do"]) {
				[switchElement release];
				success = NO;
				break;
			}
			
			while (![parser testSymbol:@"end"]) {
//				EXPElement *element = [elementTable objectForKey:[parser symbol]];
				EXPElement *element = [symbolTable symbolForName:[parser symbol]];
				[parser readSymbol];
				if ((element==nil) || !([element isMemberOfClass:[EXPStateElement class]])) {
					success = NO;
					break;
				}
				
				if (![parser testSymbol:@"="]) {
					success = NO;
					break;
				}
				
				EXPExpressionList *expressionList = [[EXPExpressionList alloc] init];
				success = [expressionList setExpressionListFromParser:parser symbolTable:symbolTable inputs:nil];
				NSMutableDictionary *dict = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
												element, @"element",  
												expressionList, @"list", 
												[NSNull null], @"exp", 
												nil];
				[switchElement addStatement:dict];
				[expressionList release];
				[dict release];
				
				if (![parser isEndOfLine] && ![parser testSymbol:@";"]) {
					success = NO;
					break;
				}
				
			} 
	
			[switches addObject:switchElement];
//			[elementTable setObject:switchElement forKey:[switchElement name]];
			[switchElement release];


		} else if ([parser testSymbol:@"plot"]) {
			EXPPlotElement *plotter = [[EXPPlotElement alloc] init];
			[plotter setModel:[self model]];
			
			do {
				NSString *name = [[NSString alloc] initWithString:[parser symbol]];
				[parser readSymbol];
				EXPElement *element = [symbolTable symbolForName:name];
				if (element==nil) {
					[name release];
					success = NO;
					break;
				}
				if ([name isEqualToString:@"t"] || [element isMemberOfClass:[EXPStateElement class]] || [element isMemberOfClass:[EXPAuxiliaryElement class]]) {
					[plotter addItem:element];
				} else {
					success = NO;
					[name release];
					break;
				}
				[name release];
				
			} while ([parser testSymbol:@","]);
			
			
			if (!([parser isEndOfLine] || [parser testSymbol:@";"] || !success)) {
				success = NO;
				[plotter release];
				break;
			}

			[plotters addObject:plotter];
			[plotter release];

		} else if ([parser testSymbol:@"print"]) {
			EXPPrintElement *printer = [[EXPPrintElement alloc] init];
			[printer setModel:[self model]];

			if ([parser testSymbol:@"to"]) {
				if (![parser isStringLiteral]) {
					success = NO;
					[printer release];
					break;
				}
				NSString *filename = [[NSString alloc] initWithString:[parser symbol]];
				[parser readSymbol];
				[printer setOutputFilename:filename];
				[filename release];
			} else {
				[printer setOutputFilename:nil];
			}
			
			do {
				NSString *name = [[NSString alloc] initWithString:[parser symbol]];
				[parser readSymbol];
				EXPElement *element = [symbolTable symbolForName:name];
				if (element==nil) {
					[name release];
					success = NO;
					break;
				}
				if ([name isEqualToString:@"t"] || [element isMemberOfClass:[EXPStateElement class]] || [element isMemberOfClass:[EXPAuxiliaryElement class]]) {
					[printer addItem:element];
				} else {
					success = NO;
					[name release];
					break;
				}
				[name release];
				
			} while ([parser testSymbol:@","]);
			
			
			if (!([parser isEndOfLine] || [parser testSymbol:@";"] || !success)) {
				success = NO;
				[printer release];
				break;
			}

			[printers addObject:printer];
			[printer release];
			
		} else if ([parser testSymbol:@"option"]) {
			EXPModel *model = [self model];
			do {
				success = [model processOption:parser/* model:model*/];
			} while ([parser testSymbol:@","]);
			
			if (!([parser isEndOfLine] || [parser testSymbol:@";"])) {
				success = NO;
				break;
			}
			
		} else if ([parser testSymbol:@"end"]) {
			break;

		} else {
			NSString *lvalue = [[NSString alloc] initWithString:[parser symbol]];
			[parser readSymbol];
			
			BOOL prime = [parser testSymbol:@"\'"];
			
			if (![parser checkSymbol:@"="]) {
				[lvalue release];
				success = NO;
				break;
			}
			
			if (prime) {
//				EXPStateElement *state = [[symbolTable symbolForName:lvalue] retain];
				EXPStateElement *state = [symbolTable symbolForName:lvalue];
				if (state==nil) {
					[lvalue release];
					success = NO;
					break;
				}

				EXPFlowElement *flow = [[EXPFlowElement alloc] init];
				NSString *flowName = [[NSString alloc] initWithFormat:@"Inflow for %@", lvalue];
				[flow setName:flowName];
				[flowName release];
//				[elementTable setObject:flow forKey:[flow name]];
				[symbolTable declareSymbol:flow];
				[flow setSheet:self];

				EXPExpressionList *expressionList = [flow expressionList];
				if ([[expressionList list] count]!=0) {
					[lvalue release];
					[flow release];
					success = NO;
					break;
				}
				
				NSMutableArray *inputs = [[NSMutableArray alloc] init];
				success = [expressionList setExpressionListFromParser:parser symbolTable:symbolTable inputs:inputs];;
				[flow setInputs:inputs];
				[inputs release];
				
				[state addInflow:flow];

				[flows addObject:flow];
				[flow release];
				
			} else {
				EXPAuxiliaryElement *aux = [[symbolTable symbolForName:lvalue] retain];
				if (aux==nil) {
					aux = [[EXPAuxiliaryElement alloc] init];
					[aux setName:lvalue];
					[aux setSheet:self];
//					[elementTable setObject:aux forKey:[aux name]];
					[symbolTable declareSymbol:aux];
					[auxiliaries addObject:aux];
				}
				
				EXPExpressionList *expressionList = [aux expressionList];
				if ([[expressionList list] count]!=0) {
					[lvalue release];
					[aux release];
					success = NO;
					break;
				}
				
				NSMutableArray *inputs = [[NSMutableArray alloc] init];
				success = [expressionList setExpressionListFromParser:parser symbolTable:symbolTable inputs:inputs];;
				[aux setInputs:inputs];
				[inputs release];				
				[aux release];
				
			}
			
			[lvalue release];
		}
	}
	
//	[self setElements:elementTable];
	[self setSymbolTable:symbolTable];
	[self setAuxiliaries:auxiliaries];
	[self setVariables:variables];
	[self setParameters:parameters];
	[self setFlows:flows];
	[self setSwitches:switches];
	[self setTables:tables];
	[self setDimensions:dimensions];
	[self setPrinters:printers];
	[self setPlotters:plotters];

//	[elementTable release];
	[auxiliaries release];
	[variables release];
	[parameters release];
	[flows release];
	[switches release];
	[tables release];
	[dimensions release];
	[printers release];
	[plotters release];

//	[parser release];
	[symbolTable release];
	
	return success;
}

- (void) setModel:(id)model
{
//	[model retain];
//	[_model release];
	_model = model;
}

- (id) model
{
	return _model;
}

- (id) name
{
	return _name;
}

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

/*- (void) setElements:(id)elements
{
	[_elements release];
	[elements retain];
	_elements = elements;
}

- (id) elements
{
	return _elements;
} */

- (void) setSymbolTable:(id)symbolTable
{
	[symbolTable retain];
	[_symbolTable release];
	_symbolTable = symbolTable;
}

- (id) symbolTable
{
	return _symbolTable;
}

- (void) setConnectors:(id)connectors
{
	[_connectors release];
	[connectors retain];
	_connectors = connectors;
}

- (id) connectors
{
	return _connectors;
}

- (void) setVariables:(id)variables
{
	[_variables release];
	[variables retain];
	_variables = variables;
}

- (id) variables
{
	return _variables;
}

- (void) setAuxiliaries:(id)auxiliaries
{
	[_auxiliaries release];
	[auxiliaries retain];
	_auxiliaries = auxiliaries;
}

- (id) auxiliaries
{
	return _auxiliaries;
}

- (void) setParameters:(id)parameters
{
	[_parameters release];
	[parameters retain];
	_parameters = parameters;
}

- (id) parameters
{
	return _parameters;
}

- (void) setFlows:(id)flows
{
	[_flows release];
	[flows retain];
	_flows = flows;
}

- (id) flows
{
	return _flows;
}

- (void) setTables:(id)tables
{
	[tables retain];
	[_tables release];
	_tables = tables;
}

- (id) tables
{
	return _tables;
}

- (void) setDimensions:(id)dimensions
{
	[dimensions retain];
	[_dimensions release];
	_dimensions = dimensions;
}

- (id) dimensions
{
	return _dimensions;
}

- (void) setSwitches:(id)switches
{
	[switches retain];
	[_switches release];
	_switches = switches;
}

- (id) switches
{
	return _switches;
}

- (void) setPlotters:(id)plotters
{
	[plotters retain];
	[_plotters release];
	_plotters = plotters;
}

- (id) plotters
{
	return _plotters;
}

- (void) setPrinters:(id)printers
{
	[printers retain];
	[_printers release];
	_printers = printers;
}

- (id) printers
{
	return _printers;
}

- (void) print
{
	NSArray *printers = [self printers];
	int i;
	for(i=0; i<[printers count]; i++) {
		EXPPrintElement *printer = [printers objectAtIndex:i];
		[printer print];
	}
}

/* - (id) retain
{
	printf("EXPSheet - (id) retain\n");
	return [super retain];
}
 */

- (void) dealloc
{
//	printf("EXPSheet - (void) dealloc\n");
	int i;
	for(i=0; i<[_variables count]; i++) {
		EXPStateElement *var = [_variables objectAtIndex:i];
		[var clear];
	}
	
	for(i=0; i<[_flows count]; i++) {
		EXPFlowElement *flow = [_flows objectAtIndex:i];
		[flow clear];
	}
	
	for(i=0; i<[_parameters count]; i++) {
		EXPParameterElement *param = [_parameters objectAtIndex:i];
		[param clear];
	}
	
	for(i=0; i<[_tables count]; i++) {
		EXPTableElement *table = [_tables objectAtIndex:i];
		[table clear];
	}
	
	for(i=0; i<[_switches count]; i++) {
		EXPTableElement *switchy = [_switches objectAtIndex:i];
		[switchy clear];
	}
	
	for(i=0; i<[_printers count]; i++) {
		EXPPrintElement *printer = [_printers objectAtIndex:i];
		[printer clear];
	}
	
	for(i=0; i<[_plotters count]; i++) {
		EXPPlotElement *plotter = [_plotters objectAtIndex:i];
		[plotter clear];
	}
	
	[_name release];
	[_symbolTable release];
//	[_elements release];
	[_connectors release];
	[_variables release];
	[_auxiliaries release];
	[_parameters release];
	[_tables release];
	[_switches release];
	[_printers release];
	[_plotters release];
	[_flows release];

	[super dealloc];
}

@end
