/*
 * Created on May 11, 2005
 */
package javax.realtime.test.traffic;

import javax.realtime.AsyncEventHandler;
import javax.realtime.PriorityParameters;
import javax.realtime.RealtimeThread;
import javax.realtime.RelativeTime;
import javax.realtime.ReleaseParameters;

import javax.realtime.DSS.DSS;
import javax.realtime.DSS.ThreadTerminatedException;

import java.util.Random;

import gov.nasa.jpf.jvm.Verify;

import gov.nasa.jpf.rtsj.test.TestClient;

import java.util.Random;

/**
 * @author gary
 */
public class Car extends RealtimeThread {
	
	public Car( String choiceMode, Intersection intersection, Random myRandom )	{
		this( choiceMode, defaultPriority, 
				null, null, null, null, intersection, myRandom );
	}
	
	public Car( String choiceMode, int priority,
			String direction, String turn, RelativeTime cost, RelativeTime deadline,
			Intersection intersection, Random myRandom ) {
		super( "Car " + (counter++), new PriorityParameters( priority ) );
		this.choiceMode = choiceMode;
		this.myRandom = myRandom;
		AsyncEventHandler overrunHandler = new AsyncEventHandler(
				null, null, null, null, null, false, null ) {
			public void handleAsyncEvent() {
				DSS.printTime();
				System.out.println( " *** car cost overrun handler invoked *** " );
			}
		};
		AsyncEventHandler missHandler = new AsyncEventHandler(
				null, null, null, null, null, false, null ) {
			public void handleAsyncEvent() {
				DSS.printTime();
				System.out.println( " *** car deadline miss handler invoked *** " );
			}
		};
		ReleaseParameters releaseParameters = new ReleaseParameters(
				cost, deadline, overrunHandler, missHandler );
		
		setReleaseParameters( releaseParameters );
		myDirection = direction;
		myTurn = turn;
		myCount = counter;
		this.intersection = intersection;
		if ( DSS.usingJPF ) {
			if ( choiceMode.equals( "nondeterministic" ) ) {
				if ( direction == null ) {
					myDirection = directions[Verify.random( 3 )];				
				}
				if ( turn == null ) {
					myTurn = turns[Verify.random( 2 ) ];					
				}				
			} else if ( choiceMode.equals( "pseudorandom" ) ) {
				// one pseudo random draw for each
				if ( direction == null ) {
					myDirection = directions[TestClient.nextInt( 4 ) ];			
				}
				if ( turn == null ) {
					myTurn = turns[TestClient.nextInt( 3 ) ];					
				}
			} else if ( choiceMode.equals( "deterministic" ) ) {
				if ( myDirection == null || myTurn == null ) {
					// myDirection and myTurn should have been explicitly set
					throw new IllegalArgumentException(
							choiceMode + " requires myDirection" + 
							" and myTurn to be explicitly set" );
				} else {
					// myDirection and myTurn are explicitlyl set
				}
			} else { // using native Java
				if ( choiceMode.equals( "nondeterministic" ) ) {
					throw new IllegalArgumentException( 
							"nondeterminstic is not a legal option under native JPF" );
				} else if ( choiceMode.equals( "pseudorandom" ) ) {			
					if ( direction == null ) {
						myDirection = directions[myRandom.nextInt( 4 ) ];			
					}
					if ( turn == null ) {
						myTurn = turns[myRandom.nextInt( 3 ) ];					
					}					
				} else if ( choiceMode.equals( "deterministic" ) ) {
					if ( myDirection == null || myTurn == null ) {
						// myDirection and myTurn should have been explicitly set
						throw new IllegalArgumentException(
								choiceMode + " requires myDirection" + 
								" and myTurn to be explicitly set" );
					}
				} else {
					throw new IllegalArgumentException(
							choiceMode + " is an unknown choice mode" );
				} 			
			}
		}
		System.out.println( this );
	}
	
	public void body() throws InterruptedException, ThreadTerminatedException {	
		intersection.enter( myDirection, myTurn );		
	}
	
	public void notifyPriorityChange() {
		// DSS.printTime();
		// System.out.println( "*** " + this + " is notified of priority change" );
		// System.out.println( resourcesHeld.isEmpty() + " " + currentEventNotice );
		if ( !resourcesHeld.isEmpty() && currentEventNotice != null ) {
			// only interested if holding resources and in a hold operation
			DSS.cancel( this );
			interrupt();
		}
	}
	
	public String toString() {
		return getName() + ", priority " + dynamicPriority() +
			", heading " + myDirection + " going " + myTurn;
	}
	
	private static int counter = 0;
	
	private int myCount;
	private String choiceMode;
	private RelativeTime myDuration;
	private Intersection intersection;
	private String myDirection;
	private String myTurn;
	private Random myRandom;
	
	private static String[] directions = { "north", "south", "east", "west" };
	
	private static String[] turns = { "straight", "left", "right" };
	
	public static int defaultPriority = 5;
}

