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

#import "EXPStateElement.h"
#import "EXPAssemblerConstants.h"
#import "EXPExpression.h"
#import "EXPUnaryOp.h"
#import "EXPBinOp.h"
#import "EXPFlowElement.h"

@implementation EXPStateElement

- (id) init
{
	self = [super init];
	if (self!=nil) {
		_inflows = [[NSMutableArray alloc] init];
		_outflows = [[NSMutableArray alloc] init];
		
		_isdelayVariable = NO;
		
		_scaleFactor = 0.0;
	}
	
	return self;
}

- (void) setOutflows:(id)outflows
{
	[outflows retain];
	[_outflows release];
	_outflows = outflows;
}

- (id) outflows
{
	return _outflows;
}

- (void) addOutflow:(EXPElement *)outflow
{
	if (outflow!=nil) {
		[[self outflows] addObject:outflow];
	}
}

- (void) setInflows:(id)inflows
{
	[inflows retain];
	[_inflows release];
	_inflows = inflows;
}

- (id) inflows
{
	return _inflows;
}

- (void) addInflow:(EXPElement *)inflow
{
	if (inflow!=nil) {
		[[self inflows] addObject:inflow];
	}
}

- (void) setIsDelayVariable:(BOOL)isdelayVariable
{
	_isdelayVariable = isdelayVariable;
}

- (BOOL) isdelayVariable
{
	return _isdelayVariable;
}

- (void) setDelayNumber:(int)delayNumber
{
	_delayNumber = delayNumber;
}

- (int) delayNumber
{
	return _delayNumber;
}

- (void) setScale:(double)scaleFactor
{
	_scaleFactor = scaleFactor;
}

- (double) scaleFactor
{
	return _scaleFactor;
}

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

- (BOOL) setElementFromParser:(EXPParser *)parser symbolTable:(EXPSymbolTable *)symbolTable inputs:(id)inputs
{
	BOOL success = [super setElementFromParser:parser symbolTable:symbolTable inputs:inputs];
	
	if ([parser testSymbol:@"delay"]) {
		[self setIsDelayVariable:YES];
	}
	
	if ([parser testSymbol:@"scale"]) {
		if ([parser checkSymbol:@"="]) {
			if ([parser isLiteral]) {
				double scale = [[parser symbol] doubleValue];
				[parser readSymbol];
				[self setScale:scale];
			}
		}
	}
	
	if ([parser testSymbol:@"label"]) {
		if (![parser testSymbol:@"="]) {
			success = NO;
		}

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

		NSString *label = [[NSString alloc] initWithString:[parser symbol]];
		[parser readSymbol];
		[self setLabel:label];
		[label release];

	}
			
	return success;
}

- (BOOL) compileNetflows:(EXPStackMachine *)machine error:(NSError **)error
{

	BOOL success = YES;
	NSArray *inflows = [self inflows];
	NSArray *outflows = [self outflows];

	if ([inflows count]>0 || [outflows count]>0) {
		int i;
		for (i=0; i<[inflows count]; i++) {
			if (i>0) {
				[machine putUInt:PSHA];
			}
	
			EXPFlowElement *flow = [inflows objectAtIndex:i];
			success = [flow compile:machine error:error withArguments:nil];
			if (!success) {
				return NO;
			}

			if (i>0) {
				[machine putUInt:ADDS];
			}
	
		}
	
		for (i=0; i<[outflows count]; i++) {
			if (i>0) {
				[machine putUInt:PSHA];
			}
	
			EXPFlowElement *flow = [outflows objectAtIndex:i];
			success = [flow compile:machine error:error withArguments:nil];
			if (!success) {
				return NO;
			}

			if (i==0) {
				[machine putUInt:NEGA];
			} else {
				[machine putUInt:SUBS];
			}
	
		}
	} else {
		[machine putUInt:LDAI];
		[machine putDouble:0.0];
	}
	
	[machine putUInt:STRG];
	[machine putUInt:[self address]];
		
	return success;
}

- (BOOL) compile:(EXPStackMachine *)machine error:(NSError **)err opcode:(unsigned int)opcode /*withArguments:(NSArray *)arguments*/
{
	BOOL success = [super compile:machine error:err opcode:(opcode + VMODE)];
	return success;
}

- (BOOL) compile:(EXPStackMachine *)machine error:(NSError **)err withArguments:(NSArray *)arguments
{
//	BOOL success = [self compile:machine error:err opcode:LDAP];
	BOOL success = YES;
	if ((arguments==nil) || ([arguments count]==0)) {
		success = [super compile:machine error:err opcode:LDAV];
	} else {
		if (![self isdelayVariable]) {
			return NO;
		}
		
		EXPExpression *delayArg = [arguments objectAtIndex:0];
		success = [delayArg compile:machine error:err];
		[machine putUInt:PSHA];
		
		if ([arguments count]>1) {
			EXPExpression *initialArg = [arguments objectAtIndex:1];
			success = [initialArg compile:machine error:err];
			[machine putUInt:PSHA];
		} else {
			[machine putUInt:PSHI];
			[machine putDouble:0.0];
		}
		
		if ([arguments count]>2) {
			EXPExpression *lagArg = [arguments objectAtIndex:2];
			success = [lagArg compile:machine error:err];
			[machine putUInt:PSHA];
		} else {
			[machine putUInt:PSHI];
			[machine putDouble:0.0];
		}
		
		[machine putUInt:DELAY];
		[machine putUInt:[self address]];
		
	}
	
	return success;
}

/*- (BOOL) isVariable
{
	return YES;
} */

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

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

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

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

- (void) dump
{
	[super dump];
	
	NSArray *inflows = [self inflows];
	int i;
	for(i=0; i<[inflows count]; i++) {
		[[inflows objectAtIndex:i] dump];
	}
	
	NSArray *outflows = [self outflows];
	for(i=0; i<[outflows count]; i++) {
		[[outflows objectAtIndex:i] dump];
	}
}

- (void) dealloc
{
//	printf("EXPStateElement - (void) dealloc\n");
	[_inflows release];
	[_outflows release];
	[super dealloc];
}

@end
