/*
 * VANETsim open source project - http://www.vanet-simulator.org
 * Copyright (C) 2008 - 2013  Andreas Tomandl, Florian Scheuer, Bernhard Gruber
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package vanetsim.scenario;

import java.awt.Color;
import java.text.ParseException;
import java.util.Iterator;
import java.util.Random;



import java.util.ArrayDeque;


import vanetsim.VanetSimStart;
import vanetsim.gui.Renderer;
import vanetsim.gui.controlpanels.ReportingControlPanel;
import vanetsim.gui.helpers.GeneralLogWriter;
import vanetsim.gui.helpers.PrivacyLogWriter;
import vanetsim.localization.Messages;
import vanetsim.map.Map;
import vanetsim.map.Node;
import vanetsim.map.Region;
import vanetsim.map.Street;
import vanetsim.routing.RoutingAlgorithm;
import vanetsim.routing.WayPoint;
import vanetsim.routing.A_Star.A_Star_Algorithm;
import vanetsim.scenario.events.BlockingObject;
import vanetsim.scenario.messages.Message;
import vanetsim.scenario.messages.PenaltyMessage;

/**
 * A vehicle which can move and communicate (if wifi is enabled).
 */
public class Vehicle extends LaneObject{
	
	/** A reference to the map so that we don't need to call this over and over again. */
	private static final Map MAP = Map.getInstance();
	
	/** A reference to the reporting control panel so that we don't need to call this over and over again. */
	private static final ReportingControlPanel REPORT_PANEL = getReportingPanel();
	
	/** When known vehicles are rechecked for outdated entries. Measured in milliseconds. */
	private static final int KNOWN_VEHICLES_TIMEOUT_CHECKINTERVAL = 5000;
	
	/** When known Road-Side-Units are rechecked for outdated entries. Measured in milliseconds. */
	private static final int KNOWN_RSUS_TIMEOUT_CHECKINTERVAL = 5000;
	
	/** How long to wait between searching the known penalties for outdated entries. Measured in milliseconds. */
	private static final int KNOWN_PENALTIES_TIMEOUT_CHECKINTERVAL = 30000;

	/** The minimum time between two newly created messages in milliseconds (does not apply to forwarded messages!). */
	private static final int MESSAGE_INTERVAL = 5000;

	/** The minimum time between two lane changes in milliseconds. */
	private static final int LANE_CHANGE_INTERVAL = 5000;

	/** If a vehicle does not move (speed=0) for this time (in milliseconds), a jam is detected and a penalty message created. */
	private static final int TIME_FOR_JAM = 5000;

	/** The radius in cm around the message destination in which the message will be flooded. */
	private static final int PENALTY_MESSAGE_RADIUS = 50000;
	
	/** The radius in cm around the message destination in which the message will be flooded. */
	private static final int PENALTY_FAKE_MESSAGE_RADIUS = 50000;

	/** The radius in cm around the message destination in which the message will be flooded. */
	private static final int PENALTY_EVA_MESSAGE_RADIUS = 50000;
	
	/** How long the penalty message will be valid (in milliseconds). 20000*/
	private static final int PENALTY_MESSAGE_VALID = 10000;
	
	/** The penalty which will be added through the message in cm. This value will be added in routing calculations. */
	private static final int PENALTY_MESSAGE_VALUE = 2000000;	// 20km
	
	/** How long the penalty itself will be valid (in milliseconds). 5000*/
	private static final int PENALTY_VALID = 5000;
	
	/** How long a vehicle waits to check if it's inside a mix. */
	private static final int MIX_CHECK_INTERVAL = 1000;
	
	/** How long the attacker waits (steps) to check if has new information about the attacked vehicle and needs to reroute. */
	private static final int ATTACKER_INTERVAL = 50;
	
	/** When the speed fluctuation is changed. Measured in milliseconds. */
	private static final int SPEED_FLUCTUATION_CHECKINTERVAL = 5000;
	
	/** When the speed fluctuation is changed. Measured in milliseconds. */
	private static final int SPEED_NO_FLUCTUATION_CHECKINTERVAL = 10000;
	
	/** Deviation from max speed limit. Simulation fluctuations in the drivers speed when reaching the speed limit. Maximum in cm/s^2 */
	private static final int SPEED_FLUCTUATION_MAX = 6;
	
	/** A global random number generator used to initialize the generators of the vehicles. */
	private static final Random RANDOM = new Random(1L);

	/** The routing algorithm used. */
	private static final RoutingAlgorithm ROUTING_ALGO = new A_Star_Algorithm();	

	/** The routing mode used. See the A_Star_Algo for details. */
	private static int routingMode_ = 1;
	
	/** The minimum time a vehicle must have traveled to get recycled. This shall prevent very shortliving 
	 * vehicles from consuming lots of CPU time for recycling. */
	private static int minTravelTimeForRecycling_ = 60000;

	/** If communication is enabled */
	private static boolean communicationEnabled_ = true;	

	/** If beacons are enabled */
	private static boolean beaconsEnabled_ = true;

	/** If mix zones are enabled */
	private static boolean mixZonesEnabled_ = true;
	
	/** If a fallback to the beaconless method shall be done in mix zones */
	private static boolean mixZonesFallbackEnabled_ = true;
	
	/** If the fallback mode only sends messages which are in flooding/broadcast mode. */
	private static boolean mixZonesFallbackFloodingOnly_ = true;

	/** How large a mix is in cm. Set in the common settings */
	private static int mixZoneRadius_ = 10000;
	
	/** How large a mix is in cm max. */
	private static int maxMixZoneRadius_ = 0;
	
	/** How long a vehicle waits to communicate again (in milliseconds). Also used for cleaning up outdated known messages. */
	private static int communicationInterval_ = 160;

	/** How long a vehicle waits to send its beacons again. */
	private static int beaconInterval_ = 240;

	/** The maximum communication distance a vehicle has. */
	private static int maximumCommunicationDistance_ = 0;

	/** An array holding all regions of the map. */
	private static Region[][] regions_;

	/** If monitoring the beacon is enabled or not. */
	private static boolean beaconMonitorEnabled_ = false;
	
	/** The minimum x coordinate which is checked during beacon monitoring. */
	private static int beaconMonitorMinX_ = -1;
	
	/** The maximum x coordinate which is checked during beacon monitoring. */
	private static int beaconMonitorMaxX_ = -1;
	
	/** The minimum y coordinate which is checked during beacon monitoring. */
	private static int beaconMonitorMinY_ = -1;
	
	/** The maximum y coordinate which is checked during beacon monitoring. */
	private static int beaconMonitorMaxY_ = -1;
	
	/** If recycling of vehicles is allowed or not */
	private static boolean recyclingEnabled_ = true;
	
	/** List of all AttackRSUs */
	private static AttackRSU arsuList[] = new AttackRSU[0];
	
	/** If attacker logging is enabled */
	private static boolean attackerDataLogged_ = false;	
	
	/** If attacker encrypted logging is enabled */
	private static boolean attackerEncryptedDataLogged_ = false;
	
	/** If attacker logging is enabled */
	private static boolean privacyDataLogged_ = false;	
	
	/** ID of the attacked vehicle */
	private static long attackedVehicleID_ = 0;
	
	/** Time for reroute of attacker */
	private static int reRouteTime_ = -1;
	
	/** encrypted beacon communication in Mix-Zones */
	private static boolean encryptedBeaconsInMix_ = false;

	/** A counter for the steady id */
	private static int steadyIDCounter = 0;
	
	/** time between silent-periods (in ms)*/
	private static int TIME_BETWEEN_SILENT_PERIODS = 10000;

	/** time of silent-periods (in ms)*/
	private static int TIME_OF_SILENT_PERIODS = 2000;
	
	/** flag to show if there is a silent period at the moment */
	private static boolean silent_period = false;
	
	/** flag to turn silent periods on/off */
	private static boolean silentPeriodsOn = false;
	
	/** time until pseudonym change in slow model */
	private static int TIME_TO_PSEUDONYM_CHANGE = 3000;
	
	/** speed limit for slow model */
	private static int  SLOW_SPEED_LIMIT = (int)(30 * 100000.0/3600);
	
	/** enable/disable slow */
	private static boolean slowOn = false;
	
	/** ids is activated */
	private static boolean idsActivated = false;
	
	/** the interval to generate fake messages */
	private static int fakeMessagesInterval_ = 10000;
	
	/** mode to send message only to vehicles within reach and to disable forwarding! (used for IDS evaluation) */
	private static boolean directCommunicationMode_ = true;
	
	
	/** How many simulation steps we wait until we send the RHCN message */
	private static int WAIT_TO_SEND_RHCN_ = 4;
	
	/** the counter for the rhcn message */
	private int waitToSendRHCNCounter_ = -1;
	
//	private static int vehiclesInSlow = 0;
	// object variables begin here

	/** The destinations this vehicle wants to visit. */
	public ArrayDeque<WayPoint> originalDestinations_;
	
	/** The <code>WayPoint</code> where this vehicles started. */
	private final WayPoint startingWayPoint_;	
	
	/** The vehicle length in cm. */
	private int vehicleLength_;
	
	/** The maximum speed of this car in cm/s. */
	private int maxSpeed_;

	/** The color of the vehicle. */
	private Color color_;
	
	/** The braking rate in cm/s^2. */
	private int brakingRate_;
	
	/** The acceleration rate in cm/s^2. */
	private int accelerationRate_ ;
	
	/** if activated the vehicle is an emergency vehicle */
	private boolean emergencyVehicle_;

	/** The maximum braking distance in cm/s*/
	private final int maxBrakingDistance_;
	
	/** Deviation from max speed limit. Simulates driver types which drive slower / faster */
	private int speedDeviation_;
	
	/** A class storing messages of different states: execute, forward and old ones. Could also be stored inside the
	 * vehicle class but it's a lot more clearly arranged like that. */ 
	private final KnownMessages knownMessages_ = new KnownMessages(this);

	/** A list of all vehicles currently known because of received beacons. */
	private final KnownVehiclesList knownVehiclesList_ = new KnownVehiclesList();
	

	/** A list of all idsprocessors currently running. */
	private final IDSProcessorList idsProcessorList_ = new IDSProcessorList(this);
	
	/** A list of all known event sources. */
	private final KnownEventSourcesList knownEventSourcesList_ = new KnownEventSourcesList(this.getID());
	
	/** A list of all Road-Side-Units currently known because of received beacons. */
	private final KnownRSUsList knownRSUsList_ = new KnownRSUsList();

	/** All known penalties. */
	private final KnownPenalties knownPenalties_ = new KnownPenalties(this);
	
	/** <code>true</code> if this vehicle has a communication device (WiFi), else <code>false</code> . */
	private boolean wiFiEnabled_;
	
	/** A random number generator for each vehicle. Primarily used for ID generation but can be used for other tasks, too. */
	private final Random ownRandom_;

	/** An ID used in communication (beacons). This might change (=> mixing zone)!It cannot be guaranteed 
	 * that this is really an unique ID as it's generated randomly! */
	private long ID_;
	
	/** An ID used to track vehicles after changing pseudonyms (for logging purpose only) */
	private int steadyID_;
	
	/** The destinations this vehicle wants to visit. */
	private ArrayDeque<WayPoint> destinations_;

	/** The new speed after the step. <code>curSpeed_</code> will be set to this in the moving-process to circumvent synchronisation problems. */
	private double newSpeed_;

	/** The new lane after the step. <code>curLane_</code> will be set to this in the moving-process to circumvent synchronisation problems. */
	private int newLane_ = 1;

	/** If set to true, this car is active and thus is drawn and moves. */
	private boolean active_ = false;

	/** An array containing ALL streets on which this vehicle will move until the next destination is reached. This can change when a rerouting is done! */
	private Street[] routeStreets_;

	/** An array with the directions on the streets corresponding to <code>routeStreets_</code> */
	private boolean[] routeDirections_;

	/** The current position in the <code>routeStreets_</code> and <code>routeDirections_</code> array */
	private int routePosition_;

	/** The current braking distance. */
	private int curBrakingDistance_;

	/** The speed at last braking distance calculation. */
	private double speedAtLastBrakingDistanceCalculation_ = 0;

	/** If the vehicle is currently in a mixing zone */
	private boolean isInMixZone_ = false;

	/** A node that we are allowed to pass. */
	private Node junctionAllowed_ = null;

	/** The maximum distance in cm this car can communicate. */
	private int maxCommDistance_;

	/** The current region. */
	private Region curRegion_;

	/** The time in milliseconds before doing the next movement. During waiting the vehicle communicates but does not 
	 * block other cars from passing. */
	private int curWaitTime_;

	/** The total time in milliseconds this vehicle traveled (excludes predefined waittimes!) */
	private int totalTravelTime_;

	/** The total distance in cm this vehicle traveled */
	private long totalTravelDistance_;

	/** If braking for the next destination should be done currently. */
	private boolean brakeForDestination_ = false;

	/** A countdown for braking. */
	private int brakeForDestinationCountdown_ = Integer.MAX_VALUE;

	/** A countdown for doing the next destination check. */
	private int destinationCheckCountdown_ = 0;

	/** A countdown to check if the minimum time between two lane changes has been reached. */
	private int laneChangeCountdown = 0;

	/** A countdown for communication. Also used for cleaning up outdated known messages. */
	private int communicationCountdown_;

	/** A countdown for sending beacons. */
	private int beaconCountdown_;

	/** A countdown for checking if inside a mix or not. */
	private int mixCheckCountdown_;

	/** A countdown for rechecking if known vehicles are outdated. */
	private int knownVehiclesTimeoutCountdown_;
	
	/** A countdown for rechecking if known RSUs are outdated. */
	private int knownRSUsTimeoutCountdown_;
	
	/** A countdown for rechecking if known penalties are outdated. */
	private int knownPenaltiesTimeoutCountdown_;

	/** A countdown for recalculating the speed fluctuation. */
	private int speedFluctuationCountdown_;
	
	/** Flag to show if a breaking because of the speed fluctuation is currently in progress */
	private boolean isBraking_ = false;
	
	/** Breaking of vehicle in fluctuation mode */
	private double fluctuation_ = 0;
	
	/** How much time has passed since the last message was created*/
	//private int lastMessageCreated = 0;

	/** How much time has passed since the last rhcn message was created*/
	private int lastRHCNMessageCreated = 0;

	/** How much time has passed since the last pcn message was created*/
	private int lastPCNMessageCreated = 0;
	
	/** How much time has passed since the last pcn forward message was created*/
	private int lastPCNFORWARDMessageCreated = 0;
	
	/** How much time has passed since the last eva message was created*/
	private int lastEVAMessageCreated = 0;
	
	/** How much time has passed since the last eva forward message was created*/
	//private int lastEVAFORWARDMessageCreated = 0;
	
	/** How much time has passed since the last eebl message was created*/
	//private int lastEEBLMessageCreated = 0;
	
	/** How much time has passed since the last fake message was created*/
	//private int lastFAKEMessageCreated = 0;

	
	
	/** How long this vehicle is waiting in a jam (in milliseconds). */
	private int stopTime_ = 0;
	
	/** How many messages this vehicle has created. */
	//private int messagesCreated_ = 0;
	
	/** How many messages this vehicle has created. Used to give the messages unique ids (vehicle id + messageCounter; note that a collusion is possible but unlikely) */
	private int messagesCounter_ = 0;
	
	
	/** How many messages this vehicle has created. */
	private int pcnMessagesCreated_ = 0;

	/** How many messages this vehicle has created. */
	private int pcnForwardMessagesCreated_ = 0;
	
	/** How many messages this vehicle has created. */
	private int evaMessagesCreated_ = 0;
	
	/** How many messages this vehicle has created. */
	private int evaForwardMessagesCreated_ = 0;
	
	/** How many messages this vehicle has created. */
	private int rhcnMessagesCreated_ = 0;
	
	/** How many messages this vehicle has created. */
	private int eeblMessagesCreated_ = 0;
	
	/** How many messages this vehicle has created. */
	private int fakeMessagesCreated_ = 0;
	
	/** How many times this vehicle changed it's ID (due to mixes) */
	private int IDsChanged_ = 0;
	
	/** If the vehicle may be reused. */
	private boolean mayBeRecycled_ = false;
	
	/** Forbid to recycle vehicle. */
	private boolean doNotRecycle_ = false;
	
	/** Used to reroute the attacker after leaving the mix-zone */
	private Boolean attackerWasInMix = false;
	
	/** Used to reroute the attacker after leaving the mix-zone */
	private Boolean attackedWasInMix = false;
	
	/** Flag is set true when the attacker finds the attacked vehicle the first time */
	private Boolean firstContact = false;

	/** Saves the node of the current mix-zone. Used for encrypted Beacons*/
	private Node curMixNode_ = null;

	/** Vehicle is waiting behind a traffic signal (do not send any message)*/
	private boolean waitingForSignal_ = false;
	
	/** A distance between vehicles based on time (ms) (between 0 - 1000)*/
	private int timeDistance_ = 1000;
	
	/** A politeness factor in % */
	private int politeness_ = 0;
	
	/** Flag to log begin and end of silent periods */
	private boolean silentPeriod = false;
	
	/** Saved Beacon 1 */
	private String savedBeacon1 = "";
	
	/** Saved Beacon 2 */
	private String savedBeacon2 = "";
	
	/** variable to log next x beacons */
	private int logNextBeacons = 0;
	
	/** flag to show if vehicle is in slow period */
	private boolean isInSlow = false;
	
	/** flag to show if vehicle already changed pseudonym in slow period */
	private boolean changedPseudonymInSlow = false;
	
	/** timestamp of entrance in slow period */
	private int slowTimestamp = 0;
	
	/** flag to show if beacons where already logged */
	private boolean slowBeaconsLogged = false;
	
	/** flag to show if vehicle just started (important for slow-model, because first slow-period won't be logged) */
	private boolean vehicleJustStartedInSlow = true;

	/** flag to move a vehicle if a emergency is behind it */
	private boolean moveOutOfTheWay_ = false;
	
	/** flag if EVA message has to be forwarded */
	private boolean forwardMessage_ = false;

	/** flag if vehicle is faking messages */
	private boolean fakingMessages_ = false;
	
	/** message type the vehicle is faking */
	private String fakeMessageType_ = "";
	
	/** A countdown for sending fake messages. */
	private int fakeMessageCountdown_ = 0;
	
	/** counter to switch between fake message types if "all" is activated */
	private int fakeMessageCounter_ = 0;
	
	/** number of fake message types */
	private int fakeMessageTypesCount = IDSProcessor.getIdsData_().length;
	
	/** emergency braking interval */
	private static int emergencyBrakingInterval_ = 600000;

	/** emergency braking */
	private boolean emergencyBraking_ = false;
	
	/** emergency braking duration */
	private int emergencyBrakingDuration_= 3000;
	
	/** emergency braking countdown */
	private int emergencyBrakingCountdown_= -1;
	
	/** flag to send EEBL messages only once */
	private boolean EEBLmessageIsCreated_ = false;
	
	/** counter how much emergency beacons should be faked */
	private int emergencyBeacons = -1;
	
	/** local blocking object */
	//private ArrayList<BlockingObject> tmpBlockings = new ArrayList<BlockingObject>();
	
	/** flag to save if vehicle is driving on the side of a road because of a emergency vehicle. */
	private boolean drivingOnTheSide_ = false;
	
	/** the emergency vehicle (faking vehicle) we are waiting for until driving back on street */
	private Vehicle waitingForVehicle_ = null;
	
	/** a flag to show if a vehicle is currently near a blocking and needs to update his position information */
	private boolean passingBlocking_ = false;
	
	/** vehicle is in a traffic jam (used to forward pcn message (ids check)) */
	private boolean inTrafficJam_ = false;
	
	/** flag if a ids processor of this vehicle needs to be fired */
	private boolean checkIDSProcessors_ = false;
	
	/** a counter to save the amount of found spamers */
	private int spamCounter_ = 0;
	

	private int EVAMessageDelay_ = 3;

	private static int minEVAMessageDelay_ = 1;
	private static int maxEVAMessageDelay_ = 10;
	
	private boolean logBeaconsAfterEvent_ = false;
	private String beaconString_ = "";
	private int amountOfLoggedBeacons_ = 0;

	/**
	 * Instantiates a new vehicle. You will get an exception if the destinations don't contain at least two <b>valid</b> elements.<br>
	 * Elements are considered as invalid if
	 * <ul>
	 * <li>no route can be found between them and the first destination</li>
	 * <li>the destination is on the same street as the first destination</li>
	 * </ul>
	 * 
	 * @param destinations		an <code>ArrayDeque</code> with at least 2 elements (start and target) indicating where to move.
	 * @param vehicleLength		the vehicle length
	 * @param maxSpeed			the maximum speed of this vehicle in cm/s
	 * @param maxCommDist		the maximum distance in cm this vehicle can communicate
	 * @param wiFiEnabled		<code>true</code> if this vehicle has a communication device (WiFi), else <code>false</code>
	 * @param emergencyVehicle	<code>true</code> vehicle is an emergency vehicle
	 * @param brakingRate		the braking rate in cm/s^2
	 * @param accelerationRate	the acceleration rate in cm/s^2
	 * @param color				the color of the vehicle, if empty the default (color.black) is used
	 * @param timeDistance		the time distance
	 * @param politeness		the politeness
	 * @throws ParseException an Exception indicating that you did not supply a valid destination list.
	 */
	public Vehicle(ArrayDeque<WayPoint> destinations, int vehicleLength, int maxSpeed, int maxCommDist, boolean wiFiEnabled, boolean emergencyVehicle, int brakingRate, int accelerationRate, int timeDistance, int politeness, int speedDeviation, Color color, boolean fakingMessages, String fakeMessageType) throws ParseException {
		if(destinations != null && destinations.size()>1){
			originalDestinations_ = destinations; 
			destinations_ = originalDestinations_.clone();			
			ID_ = RANDOM.nextLong();
			steadyID_ = steadyIDCounter++;
			vehicleLength_ = vehicleLength;
			maxSpeed_ = maxSpeed;
			emergencyVehicle_ = emergencyVehicle;
			color_ = color;
			brakingRate_ = brakingRate;
			accelerationRate_ = accelerationRate;
			timeDistance_ = timeDistance;
			politeness_ = politeness;
			maxBrakingDistance_ = maxSpeed_ + maxSpeed_ * maxSpeed_ / (2 * brakingRate_);	// see http://de.wikipedia.org/wiki/Bremsweg
			startingWayPoint_ = destinations_.pollFirst();		// take the first element and remove it from the destinations!
			wiFiEnabled_ = wiFiEnabled;
			speedDeviation_ = speedDeviation;
			ownRandom_ = new Random(RANDOM.nextLong());
			curX_ = startingWayPoint_.getX();
			curY_ = startingWayPoint_.getY();
			curPosition_ = startingWayPoint_.getPositionOnStreet();
			curStreet_ = startingWayPoint_.getStreet();
			curWaitTime_ = startingWayPoint_.getWaittime();
			
			fakingMessages_ = fakingMessages;
			fakeMessageType_ = fakeMessageType;
			curRegion_ = Map.getInstance().getRegionOfPoint(curX_,curY_);
			maxCommDistance_ = maxCommDist;
			curSpeed_ = brakingRate_/2;
			newSpeed_ = curSpeed_;
			if(curStreet_.isOneway()){
				while(!destinations_.isEmpty() && (destinations_.peekFirst().getStreet() == curStreet_ || !calculateRoute(true, false))){
					curWaitTime_ = destinations_.pollFirst().getWaittime();
				}
			} else {
				while(!destinations_.isEmpty() && (destinations_.peekFirst().getStreet() == curStreet_ || !calculateRoute(false, false))){
					curWaitTime_ = destinations_.pollFirst().getWaittime();
				}
			}
			if(destinations_.size() == 0) throw new ParseException(Messages.getString("Vehicle.errorNotEnoughDestinations"),0); //$NON-NLS-1$
			if(curWaitTime_ == 0){
				active_ = true;
				curStreet_.addLaneObject(this, curDirection_);
			}
			calculatePosition();
			
			//set the countdowns so that not all fire at the same time!
			beaconCountdown_ = (int)Math.round(curPosition_)%beaconInterval_;
			communicationCountdown_ = (int)Math.round(curPosition_)%communicationInterval_;
			mixCheckCountdown_ = (int)Math.round(curPosition_)%MIX_CHECK_INTERVAL;
			knownVehiclesTimeoutCountdown_ = (int)Math.round(curPosition_)%KNOWN_VEHICLES_TIMEOUT_CHECKINTERVAL;
			knownPenaltiesTimeoutCountdown_ = (int)Math.round(curPosition_)%KNOWN_PENALTIES_TIMEOUT_CHECKINTERVAL;
		

			knownRSUsTimeoutCountdown_ = (int)Math.round(curPosition_)%KNOWN_RSUS_TIMEOUT_CHECKINTERVAL;
			speedFluctuationCountdown_ = (int)Math.round(curPosition_)%SPEED_FLUCTUATION_CHECKINTERVAL;
			fakeMessageCountdown_ = (int)Math.round(curPosition_)%fakeMessagesInterval_;
			emergencyBrakingCountdown_ = ownRandom_.nextInt(emergencyBrakingInterval_)+1;
			
			EVAMessageDelay_ = minEVAMessageDelay_ + ownRandom_.nextInt(maxEVAMessageDelay_);
		} else throw new ParseException(Messages.getString("Vehicle.errorNotEnoughDestinations"),0); //$NON-NLS-1$
	}


	/**
	 * (Re-)Calculates the route to the next destination.
	 * 
	 * @param careAboutDirection	<code>true</code> if the direction on the current street shall be used for calculation, <code>false</code> if the direction can be chosen freely
	 * @param isReroute				<code>true</code> to indicate that this is a Rerouting. If it's a rerouting, a non-existent route does not lead to the vehicle getting inactive!
	 * 
	 * @return <code>true</code> if new route has been found, else <code>false</code> (on error)
	 */
	public boolean calculateRoute(boolean careAboutDirection, boolean isReroute){
		try{
			WayPoint nextPoint = destinations_.peekFirst();			
			if(curStreet_ == nextPoint.getStreet()){
				boolean neededDirection;
				if(curPosition_ < nextPoint.getPositionOnStreet()) neededDirection = true;
				else neededDirection = false;
				if(!careAboutDirection || neededDirection == curDirection_){
					routeStreets_ = new Street[1];
					routeStreets_[0] = curStreet_;
					routeDirections_ = new boolean[1];
					routeDirections_[0] = true;
					routePosition_ = 0;
					return true;
				} //else calculate with routing algo below!
			}
			int direction;
			if(!careAboutDirection) direction = 0;
			else if(curDirection_) direction = -1;
			else direction = 1;
			ArrayDeque<Node> routing = ROUTING_ALGO.getRouting(routingMode_, direction, curX_, curY_, curStreet_, curPosition_, nextPoint.getX(), nextPoint.getY(), nextPoint.getStreet(), nextPoint.getPositionOnStreet(), knownPenalties_.getStreets(), knownPenalties_.getDirections(), knownPenalties_.getPenalties(), knownPenalties_.getSize(), maxSpeed_);

			if(routing.size() > 0){
				if(routing.size() == 1){
					routeStreets_ = new Street[2];
					routeStreets_[0] = curStreet_;
					routeStreets_[1] = nextPoint.getStreet();
					routeDirections_ = new boolean[2];
					if(routing.peekFirst() == curStreet_.getEndNode()) routeDirections_[0] = true;
					else routeDirections_[0] = false;
					if(routing.peekFirst() == nextPoint.getStreet().getStartNode()) routeDirections_[1] = true;
					else routeDirections_[1] = false;
					routePosition_ = 0;
					return true;
				} else {
					Node nextNode;
					int i;
					boolean usedDestination = false;
					Street[] outgoingStreets;
					Street tmpStreet = curStreet_, tmpStreet2;
					routeStreets_ = new Street[routing.size() + 1];
					routeDirections_ = new boolean[routing.size() + 1];
					Iterator<Node> routeIterator = routing.iterator();
					if(routing.peekFirst() == curStreet_.getEndNode()) curDirection_ = true;
					else curDirection_ = false;
					routeStreets_[0] = curStreet_;	//add current street as first element
					boolean tmpDirection;
					if(routeIterator.next() == curStreet_.getEndNode()) tmpDirection = true;
					else tmpDirection = false;
					routeDirections_[0] = tmpDirection;
					routePosition_ = 1;
	
					while(true){	//add all streets from routing
						if(routeIterator.hasNext()) nextNode = routeIterator.next();
						else if (!usedDestination){
							usedDestination = true;
							if(nextPoint.getStreet() != tmpStreet){
								nextNode = nextPoint.getStreet().getStartNode();
								if((!tmpDirection && nextNode == tmpStreet.getStartNode()) || (tmpDirection && nextNode == tmpStreet.getEndNode())) nextNode = nextPoint.getStreet().getEndNode();
							} else break;
						} else break;
						if(tmpDirection) outgoingStreets = tmpStreet.getEndNode().getOutgoingStreets();
						else outgoingStreets = tmpStreet.getStartNode().getOutgoingStreets();
						for(i = 0; i < outgoingStreets.length; ++i){
							tmpStreet2 = outgoingStreets[i];
							if (tmpStreet2.getStartNode() == nextNode){
								tmpStreet = tmpStreet2;
								tmpDirection = false;
								break;		// found street we want to => no need to look through others
							} else if (tmpStreet2.getEndNode() == nextNode){
								tmpStreet = tmpStreet2;
								tmpDirection = true;
								break;		// found street we want to => no need to look through others
							}
						}
						routeStreets_[routePosition_] = tmpStreet;
						routeDirections_[routePosition_] = tmpDirection;
						++routePosition_;
					}
					routePosition_ = 0;
					destinationCheckCountdown_ = 0;
					return true;
				}
			} else {
				if(!isReroute && destinations_.size() < 2) {
					active_ = false;
					curWaitTime_ = Integer.MIN_VALUE;
					if(totalTravelTime_ >= minTravelTimeForRecycling_) mayBeRecycled_ = true;
				}
				return false;
			}


		} catch (Exception e){ 
			return false;
		}
	}

	/**
	 * A method to be filled when implementing IDE
	 * @param timePerStep
	 */
	
	public void adjustSpeedWithIDM(int timePerStep){
		// start vehicle
		if(curWaitTime_ != 0 && curWaitTime_ != Integer.MIN_VALUE){
			if(curWaitTime_ <= timePerStep){
				//the time the vehicle will wait until it starts driving
				curWaitTime_ = 0;
				//needs to be set for vehicle to start driving
				active_ = true;
				brakeForDestination_ = false;
				//add the vehicle to the current lane object
				curStreet_.addLaneObject(this, curDirection_);
			} else curWaitTime_ -= timePerStep;
		}
		if(active_){
			if(curWaitTime_ == 0 && curStreet_ != null){
				//as a result of this method a newSpeed_ must be set
				newSpeed_ = 270;	
				if(this.getCurStreet().getName().contains("Mittelweg")) newSpeed_ = 27000;		
			}
		}
	}
	
	/**
	 * A method to be filled when implementing MOBIL
	 * @param timePerStep
	 */
	
	public boolean checkLaneFreeMOBIL(int lane){
		//Check implementation of checkLaneFree(int) to get ideas!
		return true;
	}
	
	
	/**
	 * A method to be filled when using vehicle sjtu trace files
	 * @param timePerStep
	 */
	
	public void adjustSpeedWithSJTUTraceFiles(int timePerStep){
		// start vehicle

		//needs to be set for vehicle to start driving
		active_ = true;
		
		//the time the vehicle will wait until it starts driving
		curWaitTime_ = 0;
		
		//add the vehicle to the current lane object
		curStreet_.addLaneObject(this, curDirection_);

		//as a result of this method a newSpeed_ must be set
		newSpeed_ = 1800;	
	}
	
	/**
	 * A method to be filled when using vehicle San Francisco trace files
	 * @param timePerStep
	 */
	
	public void adjustSpeedWithSanFranciscoTraceFiles(int timePerStep){
		// start vehicle

		//needs to be set for vehicle to start driving
		active_ = true;
		
		//the time the vehicle will wait until it starts driving
		curWaitTime_ = 0;
		
		//add the vehicle to the current lane object
		curStreet_.addLaneObject(this, curDirection_);

		//as a result of this method a newSpeed_ must be set
		newSpeed_ = 1800;	
	}

	
	/**
	 * Adjust the speed if reaching crossings or other cars. It also checks if the vehicle should get active.
	 * Furthermore some cleanup in the known messages and vehicles is done and new jam messages are created if necessary.
	 * 
	 * @param timePerStep the time per step in milliseconds
	 */

	public void adjustSpeed(int timePerStep){
		waitingForSignal_ = false;
		if(curWaitTime_ != 0 && curWaitTime_ != Integer.MIN_VALUE){
			if(curWaitTime_ <= timePerStep){
				curWaitTime_ = 0;
				active_ = true;
				brakeForDestination_ = false;
				curStreet_.addLaneObject(this, curDirection_);
			} else curWaitTime_ -= timePerStep;
		}

		if(active_){
			if(curWaitTime_ == 0 && curStreet_ != null){
				//curBrakingDistance always needs to be up-to-date but speed normally doesn't change too often...
				if(curSpeed_ != speedAtLastBrakingDistanceCalculation_){
					speedAtLastBrakingDistanceCalculation_ = curSpeed_;
					//curBrakingDistance_ = (int)StrictMath.floor(((timeDistance_/1000)*curSpeed_) + curSpeed_ * curSpeed_ / (2 * brakingRate_)); <-- new version, commented out because of performance issues (vehicles are to near together when blocking occurs)
					//System.out.println(curBrakingDistance_);
					curBrakingDistance_ = (int)StrictMath.floor(0.5d + curSpeed_ + curSpeed_ * curSpeed_ / (2 * brakingRate_));
					if(curBrakingDistance_ < 500) curBrakingDistance_ = 500;
				}
				// ================================= 
				// Step 1: Check if vehicle is near destination so that it needs to brake (only checked when necessary => timer!)
				// ================================= 
				if(destinationCheckCountdown_ <= 0 && ! brakeForDestination_){
					WayPoint destinationWayPoint = destinations_.peekFirst();
					long dx = destinationWayPoint.getX() - curX_;
					long dy = destinationWayPoint.getY() - curY_;
					long distanceSquared = dx * dx + dy * dy;
					if(distanceSquared < (long)maxBrakingDistance_*maxBrakingDistance_*2){		//seems we're quite near a destination! This happens only in the last about 2-3 seconds!
						if(destinationWayPoint.getStreet() == curStreet_){ //if on the same street, the distance calculation is already correct!
							if(distanceSquared <= (long)curBrakingDistance_*curBrakingDistance_){
								if(brakeForDestinationCountdown_ > 1000) brakeForDestinationCountdown_ = 1000;
								brakeForDestination_ = true;
							} else destinationCheckCountdown_ = (int)StrictMath.floor(0.5d + ((StrictMath.sqrt(distanceSquared)-maxBrakingDistance_)/maxSpeed_)*1000);
						} else {	//not on the same street. Need to calculate the length of the rest of the way to the destination
							double distance = 0, tmpPosition = curPosition_;
							Street tmpStreet = curStreet_;
							boolean tmpDirection = curDirection_;
							int i;
							int j = routeStreets_.length-1;
							for(i = routePosition_; i < j;){
								if(tmpDirection) distance += tmpStreet.getLength() - tmpPosition;
								else distance += tmpPosition;
								++i;
								tmpDirection = routeDirections_[i];
								tmpStreet = routeStreets_[i];
								if(tmpDirection) tmpPosition = 0;
								else tmpPosition = tmpStreet.getLength();
							}
							if(tmpDirection) distance += destinations_.getFirst().getPositionOnStreet() - tmpPosition;	//left over...
							else distance += tmpPosition - destinations_.getFirst().getPositionOnStreet();			
							if(distance <= curBrakingDistance_){		//near enough to schedule braking!
								if(brakeForDestinationCountdown_ > 1000) brakeForDestinationCountdown_ = 1000;
								brakeForDestination_ = true;
							} else if(distance > maxBrakingDistance_) {	//far enough that we can sleep a little bit more
								destinationCheckCountdown_ = (int)StrictMath.floor(0.5d + (distance-maxBrakingDistance_)/maxSpeed_*1000);	//set time to recheck (using calculated distance and maximum speed!
							}	//don't need to change destinationCheckCountdown as we want to recheck next time
						}
					} else destinationCheckCountdown_ = (int)StrictMath.floor(0.5d + ((StrictMath.sqrt(distanceSquared)-maxBrakingDistance_)/maxSpeed_)*1000);		//set time to recheck (using minimum distance and maximum speed => can never be too high (vehicle might accelerate)!
					
					
					
				} else destinationCheckCountdown_ -= timePerStep;

				// ================================= 
				// Step 2: Check for vehicle/blocking in front of this one or a slower street and try to change lane
				// ================================= 
				int result = checkCurrentBraking(curLane_);
				boolean changedLane = false;
				laneChangeCountdown -= timePerStep;
				if(laneChangeCountdown < 0 && curLane_ == 0) newLane_ = 1;
				
				if(laneChangeCountdown < 0 && result == 1){
					if(curLane_ > 1){
						curBrakingDistance_ += 2000;	//make it little bit longer so that changes are not made too often if one lane has a little bit more space ;)
						int result2 = checkCurrentBraking(curLane_-1);
						curBrakingDistance_ -= 2000;
						
						if(result2 == 0 && checkLaneFree(curLane_+1)){	// only change lane if there are no obstacles on other lane or emergency vehicle is approaching
							newLane_ = curLane_ - 1;

							changedLane = true;
							
							laneChangeCountdown = LANE_CHANGE_INTERVAL;
							result = 0;
							moveOutOfTheWay_ = false;
							drivingOnTheSide_ = false;

						}
						
					}
					if(result == 1 && curStreet_.getLanesCount() > curLane_){
						curBrakingDistance_ += 2000;
						int result2 = checkCurrentBraking(curLane_+1);
						curBrakingDistance_ -= 2000;
						if(result2 == 0 && checkLaneFree(curLane_+1)){	// only change lane if there are no obstacles on other lane
							newLane_ = curLane_ + 1;

							changedLane = true;
							laneChangeCountdown = LANE_CHANGE_INTERVAL;
							result = 0;
						}
					}
				}
				// found a blocking. Check if we might change lane to prevent this
				

				boolean brakeOnce = false;
				if(result > 0){
					brakeOnce = true;
				}

				// ================================= 
				// Step 3: Check if we can change to the right lane
				// ================================= 
				if(laneChangeCountdown < 0 && curLane_ > 1 && !changedLane && result == 0){
					if(checkLaneFree(curLane_ - 1)){
						newLane_ = curLane_ - 1;
						changedLane = true;
						//if(moveOutOfTheWay_) newLane_= 0;
						laneChangeCountdown = LANE_CHANGE_INTERVAL;
						moveOutOfTheWay_ = false;
						drivingOnTheSide_ = false;

					}
				}
				
				if(drivingOnTheSide_){		
					if(next_ != null && next_.getClass().equals(Vehicle.class) && waitingForVehicle_ != null && ((Vehicle) next_).getID() == waitingForVehicle_.getID()){
						drivingOnTheSide_ = false;
						waitingForVehicle_ = null;
						laneChangeCountdown = 1000;
					}
				}

				
				if(emergencyVehicle_) newLane_ = curStreet_.getLanesCount();
				if(moveOutOfTheWay_ && !emergencyVehicle_) {
					if(forwardMessage_ && waitingForVehicle_ != null){
						
						forwardMessage_ = false;
						// find the destination for the message. Will be sent to the next junction in FRONT of us!
						boolean tmpDirection2 = !curDirection_;
						Street tmpStreet2 = curStreet_;
						Street[] crossingStreets;
						Node tmpNode;
						int k, l = 0, destX = -1, destY = -1;
						do{
							++l;
							if(tmpDirection2){
								tmpNode = tmpStreet2.getStartNode();
							} else {
								tmpNode = tmpStreet2.getEndNode();
							}
							if(tmpNode.getJunction() != null){
								destX = tmpNode.getX();
								destY = tmpNode.getY();
								break;
							}
							crossingStreets = tmpNode.getCrossingStreets();
							// find next street behind of us
							if(crossingStreets.length != 2){	// end of a street or some special case. don't forward any further
								destX = tmpNode.getX();
								destY = tmpNode.getY();
								break;
							}
							for(k = 0; k < crossingStreets.length; ++k){
								if(crossingStreets[k] != tmpStreet2){
									tmpStreet2 = crossingStreets[k];
									if(tmpStreet2.getStartNode() == tmpNode) tmpDirection2 = false;
									else tmpDirection2 = true;
									break;
								}
							}
						} while(tmpStreet2 != curStreet_ && l < 10000);	//hard limit of 10000 nodes to maximally go back or if again arriving at source street (=>circle!)
						// found destination...now insert into messagequeue
						if(destX != -1 && destY != -1){
							int direction = -1;
							if(!curDirection_) direction = 1;
							int time = Renderer.getInstance().getTimePassed();
							PenaltyMessage message = new PenaltyMessage(curX_, curY_, destX, destY, PENALTY_EVA_MESSAGE_RADIUS, time + PENALTY_MESSAGE_VALID, curStreet_, curLane_, direction, PENALTY_MESSAGE_VALUE, time + PENALTY_VALID, false, ID_, waitingForVehicle_ , "HUANG_EVA_FORWARD", false, false);
							message.setFloodingMode(false);	// enable flooding mode if within distance!						
							knownMessages_.addMessage(message, false, true);
							++evaForwardMessagesCreated_;
													
						}	
					}
					
					if(newLane_ == curStreet_.getLanesCount() && ownRandom_.nextInt(100) == 0) {
						drivingOnTheSide_ = true;
						newLane_= curLane_-1;
						changedLane = true;
						laneChangeCountdown = LANE_CHANGE_INTERVAL + 20000;
						moveOutOfTheWay_ = false;
						
						
					}			
				}

				if((curLane_ == 0 && curSpeed_ > 277) || emergencyBraking_){
					brakeOnce = true;	
				}


				// ================================= 
				// Step 4: Break or accelerate
				// ================================= 
				if(brakeForDestinationCountdown_ > 0 && brakeForDestination_) {
					brakeForDestinationCountdown_ -= timePerStep;
				}
				if((brakeForDestinationCountdown_ <= 0 && brakeForDestination_) || brakeOnce || isBraking_){

					if(isBraking_ && !(brakeOnce || (brakeForDestinationCountdown_ <= 0 && brakeForDestination_))) newSpeed_ = curSpeed_ - (fluctuation_ * (double)timePerStep/1000);
					else newSpeed_ = curSpeed_ - (brakingRate_ * (double)timePerStep/1000);

					if(!brakeOnce && newSpeed_ < brakingRate_/2) newSpeed_ = brakingRate_/2;

				}
				if(!brakeForDestination_ && !brakeOnce && !isBraking_){		//if no breaking is scheduled we can accelerate (we don't need to look forward here because cars are not allowed by law to accelerate before they're on a "faster" street :D)

					if(curSpeed_ < (curStreet_.getSpeed() + speedDeviation_)) { 
						newSpeed_ = curSpeed_ + (accelerationRate_ * (double)timePerStep/1000);
					}
				}


				// ================================= 
				// Step 5: Correct to suit hard limits
				// ================================= 
				

				if(newSpeed_ > (maxSpeed_ + speedDeviation_)) newSpeed_ = (maxSpeed_ + speedDeviation_);
				else if (newSpeed_ < 0) newSpeed_ = 0;	//no negative speed
				if((curStreet_.getSpeed() + speedDeviation_) > 0 && newSpeed_ > (curStreet_.getSpeed() + speedDeviation_) && this != Renderer.getInstance().getAttackerVehicle() && !emergencyVehicle_) newSpeed_ = (curStreet_.getSpeed() + speedDeviation_);
			}

		
			// ================================= 
			// Step 6: Check message/beacons/penalties countdown and cleanup
			// ================================= 

			// in this first simulation step, no other communication is done. So we can we can some work concerning messages and 
			// known vehicles here without synchronization problems!	
			
			
			if(speedFluctuationCountdown_ < 1){

				isBraking_ = !isBraking_;
				if(isBraking_){
			
					fluctuation_ = ownRandom_.nextInt(SPEED_FLUCTUATION_MAX);
			
					speedFluctuationCountdown_ += SPEED_FLUCTUATION_CHECKINTERVAL;
				
				}
				else{

					speedFluctuationCountdown_ += SPEED_NO_FLUCTUATION_CHECKINTERVAL;
					fluctuation_ = 0;
				}
				//currentSpeedFluctuation_ = ownRandom_.nextInt(SPEED_FLUCTUATION_MAX) + 1;
				//if(Renderer.getInstance().getMarkedVehicle() != null && Renderer.getInstance().getMarkedVehicle().equals(this)) System.out.println("Geschwindigkeit: " + currentSpeedFluctuation_);
			}
			else speedFluctuationCountdown_ -= timePerStep;
			
			
				if(EEBLmessageIsCreated_){
					emergencyBrakingCountdown_ -= timePerStep;
					if(emergencyBrakingCountdown_ < 1){
						emergencyBraking_ = false;
						EEBLmessageIsCreated_ = false;
					}
				}
				
				//else if(emergencyBrakingCountdown_ < emergencyBrakingDuration_){
					
					/*
					if(!EEBLmessageIsCreated_){
						EEBLmessageIsCreated_ = true;
						//lastMessageCreated = 0;
						// find the destination for the message. Will be sent to the next junction behind us!
						boolean tmpDirection2 = curDirection_;
						Street tmpStreet2 = curStreet_;
						Street[] crossingStreets;
						Node tmpNode;
						int k, l = 0, destX = -1, destY = -1;
						do{
							++l;
							if(tmpDirection2){
								tmpNode = tmpStreet2.getStartNode();
							} else {
								tmpNode = tmpStreet2.getEndNode();
							}
							if(tmpNode.getJunction() != null){
								destX = tmpNode.getX();
								destY = tmpNode.getY();
								break;
							}
							crossingStreets = tmpNode.getCrossingStreets();
							// find next street behind of us
							if(crossingStreets.length != 2){	// end of a street or some special case. don't forward any further
								destX = tmpNode.getX();
								destY = tmpNode.getY();
								break;
							}
							for(k = 0; k < crossingStreets.length; ++k){
								if(crossingStreets[k] != tmpStreet2){
									tmpStreet2 = crossingStreets[k];
									if(tmpStreet2.getStartNode() == tmpNode) tmpDirection2 = false;
									else tmpDirection2 = true;
									break;
								}
							}
						} while(tmpStreet2 != curStreet_ && l < 10000);	//hard limit of 10000 nodes to maximally go back or if again arriving at source street (=>circle!)
						// found destination...now insert into messagequeue
						if(destX != -1 && destY != -1){
							int direction = -1;
							if(!curDirection_) direction = 1;
							int time = Renderer.getInstance().getTimePassed();
							PenaltyMessage message = new PenaltyMessage(this.getX(), this.getY(), destX, destY, PENALTY_MESSAGE_RADIUS, time + PENALTY_MESSAGE_VALID, curStreet_, curLane_, direction, PENALTY_MESSAGE_VALUE, time + PENALTY_VALID, false, ID_, this,  "HUANG_EEBL", false, true);
							long dx = message.getDestinationX_() - curX_;
							long dy = message.getDestinationY_() - curY_;
							if((long)PENALTY_MESSAGE_RADIUS * PENALTY_MESSAGE_RADIUS >= (dx*dx + dy*dy)){
								message.setFloodingMode(true);	// enable flooding mode if within distance!
							}								
							knownMessages_.addMessage(message, true, true);

							++eeblMessagesCreated_;
						}	
						*/
						//emergencyBraking_ = true;
					//}
					
				//}
				
			
			if(isWiFiEnabled() && communicationEnabled_){
				
				if(knownMessages_.hasNewMessages()) {
					
					knownMessages_.processMessages();
				}
				communicationCountdown_ -= timePerStep;
				if(communicationCountdown_ < 1) knownMessages_.checkOutdatedMessages(true);

				knownPenaltiesTimeoutCountdown_ -= timePerStep;
				if(knownPenaltiesTimeoutCountdown_ < 1){
					if(knownPenalties_.getSize() > 0) knownPenalties_.checkValidUntil();
					knownPenaltiesTimeoutCountdown_ += KNOWN_PENALTIES_TIMEOUT_CHECKINTERVAL;
				}

				if(beaconsEnabled_){
					beaconCountdown_ -= timePerStep;

					// recheck known vehicles for outdated entries.
					if(knownVehiclesTimeoutCountdown_ < 1){
						knownVehiclesList_.checkOutdatedVehicles();
						idsProcessorList_.checkOutdatedProcessors();
						knownVehiclesTimeoutCountdown_ += KNOWN_VEHICLES_TIMEOUT_CHECKINTERVAL;
					} else knownVehiclesTimeoutCountdown_ -= timePerStep;
					
					// recheck known RSUs for outdated entries.
					if(knownRSUsTimeoutCountdown_ < 1){
						knownRSUsList_.checkOutdatedRSUs();
						knownRSUsTimeoutCountdown_ += KNOWN_RSUS_TIMEOUT_CHECKINTERVAL;
					} else knownRSUsTimeoutCountdown_ -= timePerStep;
					
				}


				
				// ================================= 
				// Step 7: Check if this vehicle is currently in a traffic jam and should create a message.
				// ================================= 
				//lastMessageCreated += timePerStep;
				lastRHCNMessageCreated += timePerStep;
				lastPCNMessageCreated += timePerStep;
				lastPCNFORWARDMessageCreated += timePerStep;
				lastEVAMessageCreated += timePerStep;
				//lastEVAFORWARDMessageCreated += timePerStep;
				//lastEEBLMessageCreated += timePerStep;
				//lastFAKEMessageCreated += timePerStep;
				if(newSpeed_ == 0){
					stopTime_ += timePerStep;
					
					if(stopTime_ > TIME_FOR_JAM && !waitingForSignal_){
						inTrafficJam_ = true;
						if(lastPCNMessageCreated >= MESSAGE_INTERVAL){
							lastPCNMessageCreated = 0;
							// find the destination for the message. Will be sent to the next junction behind us!
							boolean tmpDirection = curDirection_;
							Street tmpStreet = curStreet_;
							Street[] crossingStreets;
							Node tmpNode;
							int i, j = 0, destX = -1, destY = -1;
							do{
								++j;
								if(tmpDirection){
									tmpNode = tmpStreet.getStartNode();
								} else {
									tmpNode = tmpStreet.getEndNode();
								}
								if(tmpNode.getJunction() != null){
									destX = tmpNode.getX();
									destY = tmpNode.getY();
									break;
								}
								crossingStreets = tmpNode.getCrossingStreets();
								// find next street behind of us
								if(crossingStreets.length != 2){	// end of a street or some special case. don't forward any further
									destX = tmpNode.getX();
									destY = tmpNode.getY();
									break;
								}
								for(i = 0; i < crossingStreets.length; ++i){
									if(crossingStreets[i] != tmpStreet){
										tmpStreet = crossingStreets[i];
										if(tmpStreet.getStartNode() == tmpNode) tmpDirection = false;
										else tmpDirection = true;
										break;
									}
								}
							} while(tmpStreet != curStreet_ && j < 10000);	//hard limit of 10000 nodes to maximally go back or if again arriving at source street (=>circle!)
							// found destination...now insert into messagequeue
							if(destX != -1 && destY != -1){
								int direction = -1;
								if(!curDirection_) direction = 1;
								int time = Renderer.getInstance().getTimePassed();
								PenaltyMessage message = new PenaltyMessage(curX_, curY_, destX, destY, PENALTY_MESSAGE_RADIUS, time + PENALTY_MESSAGE_VALID, curStreet_, curLane_, direction, PENALTY_MESSAGE_VALUE, time + PENALTY_VALID, false, ID_, this,  "HUANG_PCN", false, false);
								long dx = message.getDestinationX_() - curX_;
								long dy = message.getDestinationY_() - curY_;
								if((long)PENALTY_MESSAGE_RADIUS * PENALTY_MESSAGE_RADIUS >= (dx*dx + dy*dy)){
									message.setFloodingMode(true);	// enable flooding mode if within distance!
								}								
								knownMessages_.addMessage(message, false, true);

								++pcnMessagesCreated_;
							}							
						}					
					}
				} else {
					inTrafficJam_ = false;
					stopTime_ = 0;
				}


				
				// ================================= 
				// Step 8: Check if vehicle is inside a mix zone and change vehicle ID if entering mix zone
				// ================================= 

				if(mixZonesEnabled_){
					mixCheckCountdown_ -= MIX_CHECK_INTERVAL;
					if(mixCheckCountdown_ <= 0){
						int MapMinX, MapMinY, MapMaxX, MapMaxY, RegionMinX, RegionMinY, RegionMaxX, RegionMaxY;
						int i, j, k, size;
						Node node;
						long dx, dy, mixDistanceSquared = (long)getMaxMixZoneRadius() * getMaxMixZoneRadius();
						boolean needsToMix = false;

						// Minimum x coordinate to be considered
						long tmp = curX_ - getMaxMixZoneRadius();
						if (tmp < 0) MapMinX = 0;	// Map stores only positive coordinates
						else if(tmp < Integer.MAX_VALUE) MapMinX = (int) tmp;
						else MapMinX = Integer.MAX_VALUE;

						// Maximum x coordinate to be considered
						tmp = curX_ + getMaxMixZoneRadius();
						if (tmp < 0) MapMaxX = 0;
						else if(tmp < Integer.MAX_VALUE) MapMaxX = (int) tmp;
						else MapMaxX = Integer.MAX_VALUE;

						// Minimum y coordinate to be considered
						tmp = curY_ - getMaxMixZoneRadius();
						if (tmp < 0) MapMinY = 0;
						else if(tmp < Integer.MAX_VALUE) MapMinY = (int) tmp;
						else MapMinY = Integer.MAX_VALUE;

						// Maximum y coordinate to be considered
						tmp = curY_ + getMaxMixZoneRadius();
						if (tmp < 0) MapMaxY = 0;
						else if(tmp < Integer.MAX_VALUE) MapMaxY = (int) tmp;
						else MapMaxY = Integer.MAX_VALUE;

						// Get the regions to be considered
						Region tmpregion = MAP.getRegionOfPoint(MapMinX, MapMinY);
						RegionMinX = tmpregion.getX();
						RegionMinY = tmpregion.getY();

						tmpregion = MAP.getRegionOfPoint(MapMaxX, MapMaxY);
						RegionMaxX = tmpregion.getX();
						RegionMaxY = tmpregion.getY();

						// only check those regions which are within the radius
						for(i = RegionMinX; i <= RegionMaxX; ++i){
	
							for(j = RegionMinY; j <= RegionMaxY; ++j){
								Node[] mixNodes = regions_[i][j].getMixZoneNodes();
								size = mixNodes.length;
								for(k = 0; k < size; ++k){
									node = mixNodes[k];
									// precheck if the mixing node is near enough and valid (check is not exact as its a rectangular box and not circle)
									if(node.getX() >= curX_ - node.getMixZoneRadius() && node.getX() <= curX_ + node.getMixZoneRadius() && node.getY() >= curY_ - node.getMixZoneRadius() && node.getY() <= curY_ + node.getMixZoneRadius()){
										dx = node.getX() - curX_;
										dy = node.getY() - curY_;

										mixDistanceSquared = node.getMixZoneRadius() * node.getMixZoneRadius();
										if((dx * dx + dy * dy) <= mixDistanceSquared){	// Pythagorean theorem: a^2 + b^2 = c^2 but without the needed Math.sqrt to save a little bit performance
											needsToMix = true;
											curMixNode_ = node;

											//change values to break out of all loops as we don't need to check further!
											i = RegionMaxX;
											j = RegionMaxY;
											k = mixNodes.length -1;									
										}
									} 
								}
							}
						}
						
						if(needsToMix != isInMixZone_){
							if(privacyDataLogged_){
								if(needsToMix) 	PrivacyLogWriter.log(Renderer.getInstance().getTimePassed() + ":Steady ID:" + this.steadyID_ + ":Pseudonym:" + Long.toHexString(this.ID_) + ":TraveledDistance:" + totalTravelDistance_ + ":TraveledTime:" + totalTravelTime_ + ":Node ID:" + curMixNode_.getNodeID() + ":Direction:IN" + ":Street:" + this.getCurStreet().getName() + ":StreetSpeed:" + this.getCurStreet().getSpeed() + ":VehicleSpeed:" + this.getCurSpeed() +  ":x:" + this.curX_ + ":y:" + this.curY_);
								else PrivacyLogWriter.log(Renderer.getInstance().getTimePassed() + ":Steady ID:" + this.steadyID_ + ":Pseudonym:" + Long.toHexString(this.ID_) + ":TraveledDistance:" + totalTravelDistance_ + ":TraveledTime:" + totalTravelTime_ + ":Node ID:" + curMixNode_.getNodeID() + ":Direction:OUT" + ":Street:" + this.getCurStreet().getName() + ":StreetSpeed:" + this.getCurStreet().getSpeed() + ":VehicleSpeed:" + this.getCurSpeed() + ":x:" + this.curX_ + ":y:" + this.curY_);
							}
							if(needsToMix){
								++IDsChanged_;
								ID_ = ownRandom_.nextLong();
							}
							isInMixZone_ = needsToMix;
						}
						if(!needsToMix) curMixNode_ = null;
					}
				}
			
				// ================================= 
				// Step 9: Send fake messages
				// ================================= 
				if(fakingMessages_){
					fakeMessageCountdown_ -= timePerStep;
					if(fakeMessageCountdown_ < 0){
						
						//fake messages
						fakeMessageCountdown_ = fakeMessagesInterval_;
						String messageType = fakeMessageType_;
						if(fakeMessageType_.equals("all") || fakeMessageType_.equals("Alle")) messageType = IDSProcessor.getIdsData_()[ownRandom_.nextInt(fakeMessageTypesCount)];
						
						// find the destination for the message. Will be sent to the next junction behind us! (if its pcn we send it in front)
						boolean tmpDirection2 = curDirection_;
						if(messageType.equals("HUANG_PCN")) tmpDirection2 = !curDirection_;
						
						Street tmpStreet2 = curStreet_;
						Street[] crossingStreets;
						Node tmpNode;
						int k, l = 0, destX = -1, destY = -1;
						do{
							++l;
							if(tmpDirection2){
								tmpNode = tmpStreet2.getStartNode();
							} else {
								tmpNode = tmpStreet2.getEndNode();
							}
							if(tmpNode.getJunction() != null){
								destX = tmpNode.getX();
								destY = tmpNode.getY();
								break;
							}
							crossingStreets = tmpNode.getCrossingStreets();
							// find next street behind of us
							if(crossingStreets.length != 2){	// end of a street or some special case. don't forward any further
								destX = tmpNode.getX();
								destY = tmpNode.getY();
								break;
							}
							for(k = 0; k < crossingStreets.length; ++k){
								if(crossingStreets[k] != tmpStreet2){
									tmpStreet2 = crossingStreets[k];
									if(tmpStreet2.getStartNode() == tmpNode) tmpDirection2 = false;
									else tmpDirection2 = true;
									break;
								}
							}
						} while(tmpStreet2 != curStreet_ && l < 10000);	//hard limit of 10000 nodes to maximally go back or if again arriving at source street (=>circle!)
						// found destination...now insert into messagequeue
						if(destX != -1 && destY != -1){
							int direction = -1;
							//if(!curDirection_) direction = 1;
							int time = Renderer.getInstance().getTimePassed();
							if(messageType.equals("HUANG_EVA_FORWARD")){
								PenaltyMessage message = new PenaltyMessage(curX_, curY_, destX, destY, PENALTY_FAKE_MESSAGE_RADIUS, time + PENALTY_MESSAGE_VALID, curStreet_, curLane_, direction, PENALTY_MESSAGE_VALUE, time + PENALTY_VALID, true, ID_, this,  messageType, false, true);
								message.setFloodingMode(true);	// enable flooding mode if within distance!				
								knownMessages_.addMessage(message, false, true);
							}
							else if(messageType.equals("EVA_EMERGENCY_ID")){
								if(emergencyBeacons == -1){
									emergencyBeacons = EVAMessageDelay_;
								}
				
							}
							else if(messageType.equals("HUANG_PCN")){
								//if(stopTime_ < 2000){
									//int messageX = 0;
									//int messageY = 0;
									//send message in front and only if vehicle has a street to drive left!
									/*
									if((routeStreets_.length - routePosition_) > 1){
										if(routeDirections_[(routePosition_+1)]){
											messageX = routeStreets_[(routePosition_+1)].getEndNode().getX();
											messageY = routeStreets_[(routePosition_+1)].getEndNode().getY();
										}
										else{
											messageX = routeStreets_[(routePosition_+1)].getStartNode().getX();
											messageY = routeStreets_[(routePosition_+1)].getStartNode().getY();
										}
										*/
	
										PenaltyMessage message = new PenaltyMessage(curX_, curY_, destX, destY, PENALTY_FAKE_MESSAGE_RADIUS, time + PENALTY_MESSAGE_VALID, curStreet_, curLane_, direction, PENALTY_MESSAGE_VALUE, time + PENALTY_VALID, true, ID_, this, messageType, false, true);

										long dx = message.getDestinationX_() - curX_;
										long dy = message.getDestinationY_() - curY_;
										if((long)PENALTY_MESSAGE_RADIUS * PENALTY_MESSAGE_RADIUS >= (dx*dx + dy*dy)){
											message.setFloodingMode(true);	// enable flooding mode if within distance!
										}
										knownMessages_.addMessage(message, false, true);
									//}
								//}
							}
							//else if(messageType.equals("PCN_FORWARD")){}
							else{
								PenaltyMessage message = new PenaltyMessage(curX_, curY_, destX, destY, PENALTY_FAKE_MESSAGE_RADIUS, time + PENALTY_MESSAGE_VALID, curStreet_, curLane_, direction, PENALTY_MESSAGE_VALUE, time + PENALTY_VALID, true, ID_, this, messageType, false, true);

								long dx = message.getDestinationX_() - curX_;
								long dy = message.getDestinationY_() - curY_;
								if((long)PENALTY_MESSAGE_RADIUS * PENALTY_MESSAGE_RADIUS >= (dx*dx + dy*dy)){
									message.setFloodingMode(true);	// enable flooding mode if within distance!
								}
							    knownMessages_.addMessage(message, false, true);

							}
					//		System.out.println(time + ":fake message created: " + messageType);
						}		
						++fakeMessagesCreated_;
					
						fakeMessageCounter_ = fakeMessageCounter_%fakeMessageTypesCount;
					}
				}
			}
		}			
	}
/*
	public void test(int timePerStep){
		if(knownMessages_.hasNewMessages()) {
			messageSendCounter_++;
			knownMessages_.processMessages();
		}
	
		/*
		knownPenaltiesTimeoutCountdown_ -= timePerStep;
		if(knownPenaltiesTimeoutCountdown_ < 1){
			if(knownPenalties_.getSize() > 0) knownPenalties_.checkValidUntil();
			knownPenaltiesTimeoutCountdown_ += KNOWN_PENALTIES_TIMEOUT_CHECKINTERVAL;
		}

		if(beaconsEnabled_){
			beaconCountdown_ -= timePerStep;

			// recheck known vehicles for outdated entries.
			if(knownVehiclesTimeoutCountdown_ < 1){
				knownVehiclesList_.checkOutdatedVehicles();
				idsProcessorList_.checkOutdatedProcessors();
				knownVehiclesTimeoutCountdown_ += KNOWN_VEHICLES_TIMEOUT_CHECKINTERVAL;
			} else knownVehiclesTimeoutCountdown_ -= timePerStep;
			
			// recheck known RSUs for outdated entries.
			if(knownRSUsTimeoutCountdown_ < 1){
				knownRSUsList_.checkOutdatedRSUs();
				knownRSUsTimeoutCountdown_ += KNOWN_RSUS_TIMEOUT_CHECKINTERVAL;
			} else knownRSUsTimeoutCountdown_ -= timePerStep;
			
		}
		
	}
	
	public void testa(int timePerStep){
		communicationCountdown_ -= timePerStep;
		if(communicationCountdown_ < 1) knownMessages_.checkOutdatedMessages(true);

		/*
		knownPenaltiesTimeoutCountdown_ -= timePerStep;
		if(knownPenaltiesTimeoutCountdown_ < 1){
			if(knownPenalties_.getSize() > 0) knownPenalties_.checkValidUntil();
			knownPenaltiesTimeoutCountdown_ += KNOWN_PENALTIES_TIMEOUT_CHECKINTERVAL;
		}

		if(beaconsEnabled_){
			beaconCountdown_ -= timePerStep;

			// recheck known vehicles for outdated entries.
			if(knownVehiclesTimeoutCountdown_ < 1){
				knownVehiclesList_.checkOutdatedVehicles();
				idsProcessorList_.checkOutdatedProcessors();
				knownVehiclesTimeoutCountdown_ += KNOWN_VEHICLES_TIMEOUT_CHECKINTERVAL;
			} else knownVehiclesTimeoutCountdown_ -= timePerStep;
			
			// recheck known RSUs for outdated entries.
			if(knownRSUsTimeoutCountdown_ < 1){
				knownRSUsList_.checkOutdatedRSUs();
				knownRSUsTimeoutCountdown_ += KNOWN_RSUS_TIMEOUT_CHECKINTERVAL;
			} else knownRSUsTimeoutCountdown_ -= timePerStep;
			
		}
		
	}
	
	public void test2(int timePerStep){
		/*
		if(knownMessages_.hasNewMessages()) {
			messageSendCounter_++;
			knownMessages_.processMessages();
		}
		communicationCountdown_ -= timePerStep;
		if(communicationCountdown_ < 1) knownMessages_.checkOutdatedMessages(true);

		
		knownPenaltiesTimeoutCountdown_ -= timePerStep;
		if(knownPenaltiesTimeoutCountdown_ < 1){
			if(knownPenalties_.getSize() > 0) knownPenalties_.checkValidUntil();
			knownPenaltiesTimeoutCountdown_ += KNOWN_PENALTIES_TIMEOUT_CHECKINTERVAL;
		}
/*
		if(beaconsEnabled_){
			beaconCountdown_ -= timePerStep;

			// recheck known vehicles for outdated entries.
			if(knownVehiclesTimeoutCountdown_ < 1){
				knownVehiclesList_.checkOutdatedVehicles();
				idsProcessorList_.checkOutdatedProcessors();
				knownVehiclesTimeoutCountdown_ += KNOWN_VEHICLES_TIMEOUT_CHECKINTERVAL;
			} else knownVehiclesTimeoutCountdown_ -= timePerStep;
			
			// recheck known RSUs for outdated entries.
			if(knownRSUsTimeoutCountdown_ < 1){
				knownRSUsList_.checkOutdatedRSUs();
				knownRSUsTimeoutCountdown_ += KNOWN_RSUS_TIMEOUT_CHECKINTERVAL;
			} else knownRSUsTimeoutCountdown_ -= timePerStep;
			
		}
		
	}
	
	public void test3(int timePerStep){
		/*
		if(knownMessages_.hasNewMessages()) {
			messageSendCounter_++;
			knownMessages_.processMessages();
		}
		communicationCountdown_ -= timePerStep;
		if(communicationCountdown_ < 1) knownMessages_.checkOutdatedMessages(true);

		
		knownPenaltiesTimeoutCountdown_ -= timePerStep;
		if(knownPenaltiesTimeoutCountdown_ < 1){
			if(knownPenalties_.getSize() > 0) knownPenalties_.checkValidUntil();
			knownPenaltiesTimeoutCountdown_ += KNOWN_PENALTIES_TIMEOUT_CHECKINTERVAL;
		}

		if(beaconsEnabled_){
			beaconCountdown_ -= timePerStep;

			// recheck known vehicles for outdated entries.
			if(knownVehiclesTimeoutCountdown_ < 1){
				knownVehiclesList_.checkOutdatedVehicles();
				idsProcessorList_.checkOutdatedProcessors();
				knownVehiclesTimeoutCountdown_ += KNOWN_VEHICLES_TIMEOUT_CHECKINTERVAL;
			} else knownVehiclesTimeoutCountdown_ -= timePerStep;
			
			// recheck known RSUs for outdated entries.
			if(knownRSUsTimeoutCountdown_ < 1){
				knownRSUsList_.checkOutdatedRSUs();
				knownRSUsTimeoutCountdown_ += KNOWN_RSUS_TIMEOUT_CHECKINTERVAL;
			} else knownRSUsTimeoutCountdown_ -= timePerStep;
			
		}
		
	}
	*/
	//Still in development, commented code is needed!
	/**
	 * helper class to develope politness factor
	 */
	@SuppressWarnings("unused")
	private final boolean checkPolitness(int lane){
		/*
		//Noch auszubessern: in checkLaneFree() die neededDistance wieder zur�cksetzen
		boolean vehicleInFront = false;
		boolean vehicleInFront2 = false;
		boolean vehicleBehind = false;
		boolean vehicleBehind2 = false;	
		Vehicle b = null, b2 = null, f = null, f2 = null;
		
		System.out.println("**************");
		//fahrzeug das jetzt vor uns ist:
		if(next_ != null){
			if(next_.getCurLane() == lane){	// next one is on the same lane
				//System.out.println("Fahrzeug vor uns: (1.Versuch) " + next_.curPosition_);
				if(this.equals(Renderer.getInstance().getMarkedVehicle())) ((Vehicle)next_).setColor(Color.cyan);
				f = (Vehicle)next_;
				vehicleInFront = true;
			} else {	// need to search for the next which is on our lane
				LaneObject tmpLaneObject = next_.getNext();
				while(tmpLaneObject != null){
					if(tmpLaneObject.getCurLane() == lane){
					//	System.out.println("Fahrzeug vor uns: (2. Versuch)" + tmpLaneObject.curPosition_);
						if(this.equals(Renderer.getInstance().getMarkedVehicle())) ((Vehicle)tmpLaneObject).setColor(Color.cyan);
						f = (Vehicle)tmpLaneObject;
						vehicleInFront = true;
						break;	// only check the first on our lane!
					}
					tmpLaneObject = tmpLaneObject.getNext();
				}
			}
		}
		
		if(!vehicleInFront){
			for(int i = routePosition_; i < routeStreets_.length; i++){
				boolean tmpDirection = routeDirections_[i];
				Street tmpStreet = routeStreets_[i];
				
				LaneObject tmpLaneObject = tmpStreet.getFirstLaneObject(tmpDirection);
				
				while(tmpLaneObject != null){
					if(tmpLaneObject.getCurLane() == lane){
						//System.out.println("Fahrzeug vor uns: (3. Versuch)" + tmpLaneObject.curPosition_);
						if(this.equals(Renderer.getInstance().getMarkedVehicle())) ((Vehicle)tmpLaneObject).setColor(Color.cyan);
						f = (Vehicle) tmpLaneObject;
						i=routeStreets_.length;
						break;
					}
					
					tmpLaneObject = tmpLaneObject.getNext();
				}			
			}
		}
		
		// fahrzeug das dann vor uns ist:
		if(next_ != null){
			if(next_.getCurLane() == lane+1){	// next one is on the same lane
				//System.out.println("!!!Fahrzeug dann vor uns: (1.Versuch) " + next_.curPosition_);
				if(this.equals(Renderer.getInstance().getMarkedVehicle())) ((Vehicle)next_).setColor(Color.cyan);
				f2 = (Vehicle)next_;
				vehicleInFront2 = true;
			} else {	// need to search for the next which is on our lane
				LaneObject tmpLaneObject = next_.getNext();
				while(tmpLaneObject != null){
					if(tmpLaneObject.getCurLane() == lane+1){
						//System.out.println("!!!Fahrzeug dann vor uns: (2. Versuch)" + tmpLaneObject.curPosition_);
						if(this.equals(Renderer.getInstance().getMarkedVehicle())) ((Vehicle)tmpLaneObject).setColor(Color.cyan);
						f2 = (Vehicle)tmpLaneObject;
						vehicleInFront2 = true;
						break;	// only check the first on our lane!
					}
					tmpLaneObject = tmpLaneObject.getNext();
				}
			}
		}
		
		if(!vehicleInFront2){
			for(int i = routePosition_; i < routeStreets_.length; i++){
				boolean tmpDirection = routeDirections_[i];
				Street tmpStreet = routeStreets_[i];
				
				LaneObject tmpLaneObject = tmpStreet.getFirstLaneObject(tmpDirection);
				
				while(tmpLaneObject != null){

					if(tmpLaneObject.getCurLane() == lane+1){
						//System.out.println("!!!Fahrzeug dann vor uns: (3. Versuch)" + tmpLaneObject.curPosition_);
						if(this.equals(Renderer.getInstance().getMarkedVehicle())) ((Vehicle)tmpLaneObject).setColor(Color.cyan);
						f2 = (Vehicle) tmpLaneObject;
						i = routeStreets_.length;
						break;
					}
					
					tmpLaneObject = tmpLaneObject.getNext();
				}			
			}
		}
		

		// ================================= 
		// Step 2: Check space behind
		// ================================= 

		if(previous_ == null)System.out.println("ist null");
		// check the lane object behind us (on our street)
		if(previous_ != null){
			
			if(previous_.getCurLane() == lane){	// is on the same lane
				vehicleBehind = true;
				//System.out.println("Fahrzeug hinter uns: (1. Versuch)" + previous_.curPosition_);
				if(this.equals(Renderer.getInstance().getMarkedVehicle())) ((Vehicle)previous_).setColor(Color.cyan);
				b = (Vehicle)previous_;
			} else {	// need to search for the previous one which is on our lane
				LaneObject tmpLaneObject = previous_.getPrevious();
				while(tmpLaneObject != null){
					if(tmpLaneObject.getCurLane() == lane){
						vehicleBehind = true;
					//	System.out.println("Fahrzeug hinter uns: (2. Versuch)" + previous_.curPosition_);
						if(this.equals(Renderer.getInstance().getMarkedVehicle())) ((Vehicle)tmpLaneObject).setColor(Color.cyan);
						b = (Vehicle)tmpLaneObject;
						break;	// only check the first on our lane!
					}
					tmpLaneObject = tmpLaneObject.getPrevious();
				}
			}
		}
		
		if(!vehicleBehind){
			Street[] outgoingStreets;
			Street tmpStreet = curStreet_, tmpStreet2;
			LaneObject tmpLaneObject;
			Node nextNode = null;
			boolean tmpDirection = curDirection_;
			int i;
			// check previous streets. We can't use the routing here so it's limited to streets with no junctions which makes it a bit simpler.
			int counter = 0;
			while(counter < 2){
				if(tmpDirection) nextNode = tmpStreet.getStartNode();
				else nextNode = tmpStreet.getEndNode();
				if(nextNode.getCrossingStreetsCount() != 2) break;		// don't handle junctions!
				else outgoingStreets = nextNode.getCrossingStreets();
				for(i = 0; i < outgoingStreets.length; ++i){
					tmpStreet2 = outgoingStreets[i];
					if(tmpStreet2 != tmpStreet){
						tmpStreet = tmpStreet2;
						if(lane > tmpStreet.getLanesCount()) break;
						if (tmpStreet2.getStartNode() == nextNode){
							tmpDirection = true;
							break;		// found street we want to => no need to look through others
						} else {
							tmpDirection = false;
							break;		// found street we want to => no need to look through others
						}
					}					
				}				

				if(!vehicleBehind){
					tmpLaneObject = tmpStreet.getFirstLaneObject(!tmpDirection);
					while(tmpLaneObject != null){
						if(tmpLaneObject.getCurLane() == lane && !tmpLaneObject.equals(this)){
						//	System.out.println("Fahrzeug hinter uns: (3. Versuch)" + tmpLaneObject.curPosition_);
							if(this.equals(Renderer.getInstance().getMarkedVehicle())) ((Vehicle)tmpLaneObject).setColor(Color.cyan);
							b = (Vehicle)tmpLaneObject;
							counter = 3;
							break;
						}
						tmpLaneObject = tmpLaneObject.getNext();
					}
				}
				counter++;
			}
		}
		
		
*/
		boolean vehicleBehind2 = false;	
		Vehicle b2 = null; 
		double distance = 0;
		
		// check the lane object then before us (on our street)
		if(previous_ != null){
			if(previous_.getCurLane() == lane+1){	// is on the same lane
				vehicleBehind2 = true;
			//	System.out.println("!!!Fahrzeug dann hinter uns: (1. Versuch)" + previous_.curPosition_);
				if(this.equals(Renderer.getInstance().getMarkedVehicle())) ((Vehicle)previous_).setColor(Color.cyan);
				b2 = (Vehicle)previous_;
			} else {	// need to search for the previous one which is on our lane
				LaneObject tmpLaneObject = previous_.getPrevious();
				while(tmpLaneObject != null){
					if(tmpLaneObject.getCurLane() == lane+1){
						vehicleBehind2 = true;
					//	System.out.println("!!!Fahrzeug dann hinter uns: (2. Versuch)" + previous_.curPosition_);
						if(this.equals(Renderer.getInstance().getMarkedVehicle())) ((Vehicle)tmpLaneObject).setColor(Color.cyan);
						b2 = (Vehicle)tmpLaneObject;
						break;	// only check the first on our lane!
					}
					tmpLaneObject = tmpLaneObject.getPrevious();
				}
			}
		}
		if(vehicleBehind2){
			distance = Math.abs(curPosition_ - b2.curPosition_);
		}
		else{
			if(curDirection_) distance = curPosition_;
			else distance = curStreet_.getLength() - curPosition_;
		}
	
	//	System.out.println("distance: " + distance);
		
		if(!vehicleBehind2){
			Street[] outgoingStreets;
			Street tmpStreet = curStreet_, tmpStreet2;
			LaneObject tmpLaneObject;
			Node nextNode = null;
			boolean tmpDirection = curDirection_;
			int i;
			// check previous streets. We can't use the routing here so it's limited to streets with no junctions which makes it a bit simpler.
			int counter = 0;
			
			while(counter < 3){
				//System.out.println("counter: " + counter);
				if(tmpDirection) nextNode = tmpStreet.getStartNode();
				else nextNode = tmpStreet.getEndNode();
				if(nextNode.getCrossingStreetsCount() != 2) break;		// don't handle junctions!
				else outgoingStreets = nextNode.getCrossingStreets();
				for(i = 0; i < outgoingStreets.length; ++i){
					tmpStreet2 = outgoingStreets[i];
					if(tmpStreet2 != tmpStreet){
						tmpStreet = tmpStreet2;
						if(lane+1 > tmpStreet.getLanesCount()) break;
						if (tmpStreet2.getStartNode() == nextNode){
							tmpDirection = true;
							break;		// found street we want to => no need to look through others
						} else {
							tmpDirection = false;
							break;		// found street we want to => no need to look through others
						}
					}					
				}				

				if(!vehicleBehind2){
					tmpLaneObject = tmpStreet.getFirstLaneObject(!tmpDirection);
					while(tmpLaneObject != null){
						if(tmpLaneObject.getCurLane() == lane + 1 && !tmpLaneObject.equals(this)){
						//	System.out.println("!!!Fahrzeug dann hinter uns: (3. Versuch)" + tmpLaneObject.curPosition_);
							counter = 3;
							if(tmpDirection) distance =  tmpStreet.getLength()-tmpLaneObject.getCurPosition()+distance;
							else distance = tmpLaneObject.getCurPosition()+distance;
							
							if(this.equals(Renderer.getInstance().getMarkedVehicle())) ((Vehicle)tmpLaneObject).setColor(Color.cyan);
							b2 = (Vehicle)tmpLaneObject;

							break;
						}
						tmpLaneObject = tmpLaneObject.getNext();
					}
				}
				counter ++;
				if(counter < 3)distance += tmpStreet.getLength();
			}
		}

		if(b2 != null){
			if(curSpeed_ >= b2.curSpeed_){
				//System.out.println("hinterer langsamer");
				return true;
			}
			float t = (float) ((b2.curSpeed_ - curSpeed_)/accelerationRate_);
			//System.out.println("distanz ben�tigt: " + b2.curSpeed_ * t);
		//	System.out.println("distanz vorhanden: " + (distance-b2.curBrakingDistance_));
			//System.out.println("braking distance" + b2.curBrakingDistance_);
			if((distance-b2.curBrakingDistance_) > ((politeness_/100) * (b2.curSpeed_*t))) return true;
			else return false;

		}
		else return true;
		//code need, still developing
		/*
		float t = (float) ((maxSpeed_ - curSpeed_)/accelerationRate_);
		if(b2 != null){
			//if(b2.curPosition_ - curPosition_)
			System.out.println(b2.curSpeed_ * t);
		}
		
		System.out.println("**************");
		*/
		/*
		boolean foundNextVehicle = false;
		// check the lane object in front of us (on our street). This is separated from the loop beneath as this is done most of the time!
		if(next_ != null){
			if(next_.getCurLane() == lane){	// next one is on the same lane
				foundNextVehicle = true;
				if((curDirection_ && next_.getCurPosition()-curPosition_ < curBrakingDistance_) || (!curDirection_ && curPosition_-next_.getCurPosition() < curBrakingDistance_)){
					if(curSpeed_ > next_.getCurSpeed()-brakingRate_) return 1;
				}
			} else {	// need to search for the next which is on our lane
				LaneObject tmpLaneObject = next_.getNext();
				while(tmpLaneObject != null){
					if(tmpLaneObject.getCurLane() == lane){
						foundNextVehicle = true;
						if((curDirection_ && tmpLaneObject.getCurPosition()-curPosition_ < curBrakingDistance_) || (!curDirection_ && curPosition_-tmpLaneObject.getCurPosition() < curBrakingDistance_)){
							if(curSpeed_ > next_.getCurSpeed()-brakingRate_) return 1;
						}
						break;	// only check the first on our lane!
					}
					tmpLaneObject = tmpLaneObject.getNext();
				}
			}
		}
		// didn't need to brake because of vehicle directly in front of us
		double distance;
		if(curDirection_) distance = curStreet_.getLength() - curPosition_;
		else distance = curPosition_;
		// only do the big calculation if the current street is empty AND the remainder of the current street is shorter than the braking distance
		if(distance < curBrakingDistance_){
			Street tmpStreet = curStreet_;
			LaneObject tmpLaneObject;
			Node junctionNode, nextNode;
			boolean tmpDirection = curDirection_;
			boolean gotJunctionPermission = false;
			int tmpLane = lane;
			int i;
			int j = routeStreets_.length-1;

			// check next streets that we will visit. If routing is empty this automatically skips (which is what we actually want)
			for(i = routePosition_; i < j;){
				//check for junctions
				if(tmpDirection) junctionNode = tmpStreet.getEndNode();
				else junctionNode = tmpStreet.getStartNode();
				if(junctionNode.getJunction() != null){
					if(junctionAllowed_ != junctionNode){
						if(routeDirections_[i+1]) nextNode = routeStreets_[i+1].getEndNode();
						else nextNode = routeStreets_[i+1].getStartNode();
						if(junctionNode.isHasTrafficSignal_()){
							if(junctionNode.getJunction().canPassTrafficLight(this, tmpStreet, nextNode)){	
								junctionAllowed_ = junctionNode;
								gotJunctionPermission = true;
							}
							else {
								waitingForSignal_ = true;
								return 2;
							}
						}
						else{
							int priority;
							if(tmpDirection) priority = junctionNode.getJunction().getJunctionPriority(tmpStreet.getStartNode(), nextNode);
							else priority = junctionNode.getJunction().getJunctionPriority(tmpStreet.getEndNode(), nextNode);
							if(priority != 1){	// don't do anything on priority streets
								// don't turn off faster than about 35km/h
								if(curSpeed_ > 1000){
									return 2;
								} else if(priority > 2){
									junctionNode.getJunction().addWaitingVehicle(this, priority);
									if(!junctionNode.getJunction().canPassJunction(this, priority, nextNode)) return 2;
									else {
										junctionAllowed_ = junctionNode;
										gotJunctionPermission = true;
									}
								}
							}
						}
					}
				}
				//get next street
				++i;
				tmpDirection = routeDirections_[i];
				tmpStreet = routeStreets_[i];
				if(tmpLane > tmpStreet.getLanesCount()) tmpLane = tmpStreet.getLanesCount();

				// Check if next street has smaller speed limit
				if(tmpStreet.getSpeed() < curSpeed_) {
					if(gotJunctionPermission) {
						junctionAllowed_.getJunction().allowOtherVehicle();
						junctionAllowed_ = null;
					}					
					return 2;
				}

				// Check if first lane object of next street on our lane forces us to stop
				if(!foundNextVehicle){
					tmpLaneObject = tmpStreet.getFirstLaneObject(tmpDirection);
					while(tmpLaneObject != null){
						if(tmpLaneObject.getCurLane() == tmpLane){
							foundNextVehicle = true;
							if((tmpDirection && tmpLaneObject.getCurPosition()+distance < curBrakingDistance_) || (!tmpDirection && tmpStreet.getLength()-tmpLaneObject.getCurPosition()+distance < curBrakingDistance_)){
								if(curSpeed_ > tmpLaneObject.getCurSpeed()-brakingRate_){
									if(gotJunctionPermission) {
										junctionAllowed_.getJunction().allowOtherVehicle();
										junctionAllowed_ = null;
									}	
									return 1;
								}
							}
							break;
						}
						tmpLaneObject = tmpLaneObject.getNext();
					}
				}

				// calculate distance of the whole street.
				distance += tmpStreet.getLength();
				// We can stop processing the next one if we get longer than braking distance
				if(distance > curBrakingDistance_) break;
				if(tmpStreet == destinations_.peekFirst().getStreet()) break;

			}
		}
		return 0;
		*/
	}

	
	/**
	 * Check if braking is necessary on the specified lane.
	 * 
	 * @param lane	the lane to check
	 * 
	 * @return <code>0</code> if braking is not necessary, <code>1</code> if braking is necessary because of an object on a lane,
	 * 	<code>2</code> if braking is necessary because of a lower speed street or junction
	 */
	private final int checkCurrentBraking(int lane){
		boolean foundNextVehicle = false;
	
				
		// check the lane object in front of us (on our street). This is separated from the loop beneath as this is done most of the time!
		if(next_ != null){
			if(next_.getCurLane() == lane){	// next one is on the same lane
				foundNextVehicle = true;
				if((curDirection_ && next_.getCurPosition()-curPosition_ < curBrakingDistance_) || (!curDirection_ && curPosition_-next_.getCurPosition() < curBrakingDistance_)){
					//if(curSpeed_ > 3600 && knownPenalties_.streetIsBlocked(curStreet_, 3))return 1;
					if(curSpeed_ > next_.getCurSpeed()-brakingRate_){
						if(!next_.getClass().equals(BlockingObject.class)){
							if(emergencyVehicle_){
								if(lastEVAMessageCreated >= MESSAGE_INTERVAL){
									lastEVAMessageCreated = 0;
									// find the destination for the message. Will be sent to the next junction in FRONT of us!
									boolean tmpDirection2 = !curDirection_;
									Street tmpStreet2 = curStreet_;
									Street[] crossingStreets;
									Node tmpNode;
									int k, l = 0, destX = -1, destY = -1;
									do{
										++l;
										if(tmpDirection2){
											tmpNode = tmpStreet2.getStartNode();
										} else {
											tmpNode = tmpStreet2.getEndNode();
										}
										if(tmpNode.getJunction() != null){
											destX = tmpNode.getX();
											destY = tmpNode.getY();
											break;
										}
										crossingStreets = tmpNode.getCrossingStreets();
										// find next street behind of us
										if(crossingStreets.length != 2){	// end of a street or some special case. don't forward any further
											destX = tmpNode.getX();
											destY = tmpNode.getY();
											break;
										}
										for(k = 0; k < crossingStreets.length; ++k){
											if(crossingStreets[k] != tmpStreet2){
												tmpStreet2 = crossingStreets[k];
												if(tmpStreet2.getStartNode() == tmpNode) tmpDirection2 = false;
												else tmpDirection2 = true;
												break;
											}
										}
									} while(tmpStreet2 != curStreet_ && l < 10000);	//hard limit of 10000 nodes to maximally go back or if again arriving at source street (=>circle!)
									// found destination...now insert into messagequeue
									if(destX != -1 && destY != -1){
										int direction = -1;
										if(!curDirection_) direction = 1;
										int time = Renderer.getInstance().getTimePassed();
										PenaltyMessage message = new PenaltyMessage(curX_, curY_, destX, destY, PENALTY_EVA_MESSAGE_RADIUS, time + PENALTY_MESSAGE_VALID, curStreet_, curLane_, direction, PENALTY_MESSAGE_VALUE, time + PENALTY_VALID, false, ID_, this, "EVA_EMERGENCY_ID", true, true);
										message.setFloodingMode(true);	// enable flooding mode if within distance!						
										knownMessages_.addMessage(message, false, true);
										
										++evaMessagesCreated_;
									}							
								}	

							}
							else if(((Vehicle)next_).isInTrafficJam_()  && !((Vehicle)next_).waitingForSignal_ && curSpeed_ > 0){
								
								if(lastPCNFORWARDMessageCreated >= MESSAGE_INTERVAL){
									lastPCNFORWARDMessageCreated = 0;
									// find the destination for the message. Will be sent to the next junction behind us!
									boolean tmpDirection = curDirection_;
									Street tmpStreet = curStreet_;
									Street[] crossingStreets;
									Node tmpNode;
									int i, j = 0, destX = -1, destY = -1;
									do{
										++j;
										if(tmpDirection){
											tmpNode = tmpStreet.getStartNode();
										} else {
											tmpNode = tmpStreet.getEndNode();
										}
										if(tmpNode.getJunction() != null){
											destX = tmpNode.getX();
											destY = tmpNode.getY();
											break;
										}
										crossingStreets = tmpNode.getCrossingStreets();
										// find next street behind of us
										if(crossingStreets.length != 2){	// end of a street or some special case. don't forward any further
											destX = tmpNode.getX();
											destY = tmpNode.getY();
											break;
										}
										for(i = 0; i < crossingStreets.length; ++i){
											if(crossingStreets[i] != tmpStreet){
												tmpStreet = crossingStreets[i];
												if(tmpStreet.getStartNode() == tmpNode) tmpDirection = false;
												else tmpDirection = true;
												break;
											}
										}
									} while(tmpStreet != curStreet_ && j < 10000);	//hard limit of 10000 nodes to maximally go back or if again arriving at source street (=>circle!)
									// found destination...now insert into messagequeue
									if(destX != -1 && destY != -1){
										int direction = -1;
										if(!curDirection_) direction = 1;
										int time = Renderer.getInstance().getTimePassed();
										PenaltyMessage message = new PenaltyMessage(curX_, curY_, destX, destY, PENALTY_MESSAGE_RADIUS, time + PENALTY_MESSAGE_VALID, curStreet_, curLane_, direction, PENALTY_MESSAGE_VALUE, time + PENALTY_VALID, false, ID_, null,  "PCN_FORWARD", false, false);
										long dx = message.getDestinationX_() - curX_;
										long dy = message.getDestinationY_() - curY_;
										if((long)PENALTY_MESSAGE_RADIUS * PENALTY_MESSAGE_RADIUS >= (dx*dx + dy*dy)){
											message.setFloodingMode(true);	// enable flooding mode if within distance!
										}									
										knownMessages_.addMessage(message, false, true);

										++pcnForwardMessagesCreated_;
									}	
														
								}
							}
								
							return 1;
						}
						else if(((BlockingObject) next_).getPenaltyType_().equals("HUANG_RHCN") &&  curSpeed_ < 360) return 0;
						else {
							passingBlocking_ = true;
							if(((BlockingObject) next_).getPenaltyType_().equals("HUANG_RHCN"))	{
								if(lastRHCNMessageCreated >= MESSAGE_INTERVAL){
									if(waitToSendRHCNCounter_ < 0)waitToSendRHCNCounter_ = WAIT_TO_SEND_RHCN_;
									else if(waitToSendRHCNCounter_ > 0) waitToSendRHCNCounter_--;
									else{	
										waitToSendRHCNCounter_ = -1;	
										
									
										lastRHCNMessageCreated = 0;
										// find the destination for the message. Will be sent to the next junction behind us!
										boolean tmpDirection2 = curDirection_;
										Street tmpStreet2 = curStreet_;
										Street[] crossingStreets;
										Node tmpNode;
										int k, l = 0, destX = -1, destY = -1;
										do{
											++l;
											if(tmpDirection2){
												tmpNode = tmpStreet2.getStartNode();
											} else {
												tmpNode = tmpStreet2.getEndNode();
											}
											if(tmpNode.getJunction() != null){
												destX = tmpNode.getX();
												destY = tmpNode.getY();
												break;
											}
											crossingStreets = tmpNode.getCrossingStreets();
											// find next street behind of us
											if(crossingStreets.length != 2){	// end of a street or some special case. don't forward any further
												destX = tmpNode.getX();
												destY = tmpNode.getY();
												break;
											}
											for(k = 0; k < crossingStreets.length; ++k){
												if(crossingStreets[k] != tmpStreet2){
													tmpStreet2 = crossingStreets[k];
													if(tmpStreet2.getStartNode() == tmpNode) tmpDirection2 = false;
													else tmpDirection2 = true;
													break;
												}
											}
										} while(tmpStreet2 != curStreet_ && l < 10000);	//hard limit of 10000 nodes to maximally go back or if again arriving at source street (=>circle!)
										// found destination...now insert into messagequeue
										if(destX != -1 && destY != -1){
											int direction = -1;
											if(!curDirection_) direction = 1;
											int time = Renderer.getInstance().getTimePassed();
											PenaltyMessage message = new PenaltyMessage(((BlockingObject) next_).getX(), ((BlockingObject) next_).getY(), destX, destY, PENALTY_MESSAGE_RADIUS, time + PENALTY_MESSAGE_VALID, curStreet_, curLane_, direction, PENALTY_MESSAGE_VALUE, time + PENALTY_VALID, false, ID_, this, "HUANG_RHCN", false, true);
											long dx = message.getDestinationX_() - curX_;
											long dy = message.getDestinationY_() - curY_;
											if((long)PENALTY_MESSAGE_RADIUS * PENALTY_MESSAGE_RADIUS >= (dx*dx + dy*dy)){
												message.setFloodingMode(true);	// enable flooding mode if within distance!
											}								
											knownMessages_.addMessage(message, false, true);

											++rhcnMessagesCreated_;
										}	
									}						
								}								
							}
							return 1;
						}
					}	
					

				}
			} else {	// need to search for the next which is on our lane
				LaneObject tmpLaneObject = next_.getNext();
				while(tmpLaneObject != null){
					if(tmpLaneObject.getCurLane() == lane){
						foundNextVehicle = true;
						if((curDirection_ && tmpLaneObject.getCurPosition()-curPosition_ < curBrakingDistance_) || (!curDirection_ && curPosition_-tmpLaneObject.getCurPosition() < curBrakingDistance_)){
							if(curSpeed_ > next_.getCurSpeed()-brakingRate_){
								if(!next_.getClass().equals(BlockingObject.class)){
									if(emergencyVehicle_){
										if(lastEVAMessageCreated >= MESSAGE_INTERVAL){
											lastEVAMessageCreated = 0;
											// find the destination for the message. Will be sent to the next junction in FRONT of us!
											boolean tmpDirection2 = !curDirection_;
											Street tmpStreet2 = curStreet_;
											Street[] crossingStreets;
											Node tmpNode;
											int k, l = 0, destX = -1, destY = -1;
											do{
												++l;
												if(tmpDirection2){
													tmpNode = tmpStreet2.getStartNode();
												} else {
													tmpNode = tmpStreet2.getEndNode();
												}
												if(tmpNode.getJunction() != null){
													destX = tmpNode.getX();
													destY = tmpNode.getY();
													break;
												}
												crossingStreets = tmpNode.getCrossingStreets();
												// find next street behind of us
												if(crossingStreets.length != 2){	// end of a street or some special case. don't forward any further
													destX = tmpNode.getX();
													destY = tmpNode.getY();
													break;
												}
												for(k = 0; k < crossingStreets.length; ++k){
													if(crossingStreets[k] != tmpStreet2){
														tmpStreet2 = crossingStreets[k];
														if(tmpStreet2.getStartNode() == tmpNode) tmpDirection2 = false;
														else tmpDirection2 = true;
														break;
													}
												}
											} while(tmpStreet2 != curStreet_ && l < 10000);	//hard limit of 10000 nodes to maximally go back or if again arriving at source street (=>circle!)
											// found destination...now insert into messagequeue
											if(destX != -1 && destY != -1){
												int direction = -1;
												if(!curDirection_) direction = 1;
												int time = Renderer.getInstance().getTimePassed();
												
												PenaltyMessage message = new PenaltyMessage(curX_, curY_, destX, destY, PENALTY_EVA_MESSAGE_RADIUS, time + PENALTY_MESSAGE_VALID, curStreet_, curLane_, direction, PENALTY_MESSAGE_VALUE, time + PENALTY_VALID, false, ID_, this, "EVA_EMERGENCY_ID", true, true);
												message.setFloodingMode(true);	// enable flooding mode if within distance!								
												knownMessages_.addMessage(message, false, true);
										

												++evaMessagesCreated_;
											}							
										}	
									}
									else if(((Vehicle)next_).isInTrafficJam_() && !((Vehicle)next_).waitingForSignal_ && curSpeed_ > 0){
										
										if(lastPCNFORWARDMessageCreated >= MESSAGE_INTERVAL){
											lastPCNFORWARDMessageCreated = 0;
											// find the destination for the message. Will be sent to the next junction behind us!
											boolean tmpDirection = curDirection_;
											Street tmpStreet = curStreet_;
											Street[] crossingStreets;
											Node tmpNode;
											int i, j = 0, destX = -1, destY = -1;
											do{
												++j;
												if(tmpDirection){
													tmpNode = tmpStreet.getStartNode();
												} else {
													tmpNode = tmpStreet.getEndNode();
												}
												if(tmpNode.getJunction() != null){
													destX = tmpNode.getX();
													destY = tmpNode.getY();
													break;
												}
												crossingStreets = tmpNode.getCrossingStreets();
												// find next street behind of us
												if(crossingStreets.length != 2){	// end of a street or some special case. don't forward any further
													destX = tmpNode.getX();
													destY = tmpNode.getY();
													break;
												}
												for(i = 0; i < crossingStreets.length; ++i){
													if(crossingStreets[i] != tmpStreet){
														tmpStreet = crossingStreets[i];
														if(tmpStreet.getStartNode() == tmpNode) tmpDirection = false;
														else tmpDirection = true;
														break;
													}
												}
											} while(tmpStreet != curStreet_ && j < 10000);	//hard limit of 10000 nodes to maximally go back or if again arriving at source street (=>circle!)
											// found destination...now insert into messagequeue
											if(destX != -1 && destY != -1){
												int direction = -1;
												if(!curDirection_) direction = 1;
												int time = Renderer.getInstance().getTimePassed();
												PenaltyMessage message = new PenaltyMessage(curX_, curY_, destX, destY, PENALTY_MESSAGE_RADIUS, time + PENALTY_MESSAGE_VALID, curStreet_, curLane_, direction, PENALTY_MESSAGE_VALUE, time + PENALTY_VALID, false, ID_, this,  "PCN_FORWARD", false, false);
												long dx = message.getDestinationX_() - curX_;
												long dy = message.getDestinationY_() - curY_;
												if((long)PENALTY_MESSAGE_RADIUS * PENALTY_MESSAGE_RADIUS >= (dx*dx + dy*dy)){
													message.setFloodingMode(true);	// enable flooding mode if within distance!
												}							
												knownMessages_.addMessage(message, false, true);

												++pcnForwardMessagesCreated_;
											}															
										}
									}
									return 1;
								}
								else if(((BlockingObject) next_).getPenaltyType_().equals("HUANG_RHCN") &&  curSpeed_ < 360 ) return 0;
								else{
									//for(StartBlocking blocks:EventList.getInstance().getCurrentBlockingsArrayList()) if(blocks.getStreet().equals(curStreet_) && blocks.isFirst_() && blocks.getPenaltyType_().equals("HUANG_RHCN")){
										//blocks.setFirst_(false);
									passingBlocking_ = true;
									if(((BlockingObject) next_).getPenaltyType_().equals("HUANG_RHCN"))	{	
										if(lastRHCNMessageCreated >= MESSAGE_INTERVAL){
											lastRHCNMessageCreated = 0;
											// find the destination for the message. Will be sent to the next junction behind us!
											boolean tmpDirection2 = curDirection_;
											Street tmpStreet2 = curStreet_;
											Street[] crossingStreets;
											Node tmpNode;
											int k, l = 0, destX = -1, destY = -1;
											do{
												++l;
												if(tmpDirection2){
													tmpNode = tmpStreet2.getStartNode();
												} else {
													tmpNode = tmpStreet2.getEndNode();
												}
												if(tmpNode.getJunction() != null){
													destX = tmpNode.getX();
													destY = tmpNode.getY();
													break;
												}
												crossingStreets = tmpNode.getCrossingStreets();
												// find next street behind of us
												if(crossingStreets.length != 2){	// end of a street or some special case. don't forward any further
													destX = tmpNode.getX();
													destY = tmpNode.getY();
													break;
												}
												for(k = 0; k < crossingStreets.length; ++k){
													if(crossingStreets[k] != tmpStreet2){
														tmpStreet2 = crossingStreets[k];
														if(tmpStreet2.getStartNode() == tmpNode) tmpDirection2 = false;
														else tmpDirection2 = true;
														break;
													}
												}
											} while(tmpStreet2 != curStreet_ && l < 10000);	//hard limit of 10000 nodes to maximally go back or if again arriving at source street (=>circle!)
											// found destination...now insert into messagequeue
											if(destX != -1 && destY != -1){
												int direction = -1;
												if(!curDirection_) direction = 1;
												int time = Renderer.getInstance().getTimePassed();
												PenaltyMessage message = new PenaltyMessage(((BlockingObject) next_).getX(), ((BlockingObject) next_).getY(), destX, destY, PENALTY_MESSAGE_RADIUS, time + PENALTY_MESSAGE_VALID, curStreet_, curLane_, direction, PENALTY_MESSAGE_VALUE, time + PENALTY_VALID, false, ID_, this, "HUANG_RHCN", false, true);
												long dx = message.getDestinationX_() - curX_;
												long dy = message.getDestinationY_() - curY_;
												if((long)PENALTY_MESSAGE_RADIUS * PENALTY_MESSAGE_RADIUS >= (dx*dx + dy*dy)){
													message.setFloodingMode(true);	// enable flooding mode if within distance!
												}								
												knownMessages_.addMessage(message, false, true);
												++rhcnMessagesCreated_;

											}							
										}	
									}
									return 1;
								}
							}							}
						break;	// only check the first on our lane!
					}
					tmpLaneObject = tmpLaneObject.getNext();
				}
			}
		}
		// didn't need to brake because of vehicle directly in front of us
		double distance;
		if(curDirection_) distance = curStreet_.getLength() - curPosition_;
		else distance = curPosition_;
		// only do the big calculation if the current street is empty AND the remainder of the current street is shorter than the braking distance
		if(distance < curBrakingDistance_){
			Street tmpStreet = curStreet_;
			LaneObject tmpLaneObject;
			Node junctionNode, nextNode;
			boolean tmpDirection = curDirection_;
			boolean gotJunctionPermission = false;
			int tmpLane = lane;
			int i;
			int j = routeStreets_.length-1;

			// check next streets that we will visit. If routing is empty this automatically skips (which is what we actually want)
			for(i = routePosition_; i < j;){
				//check for junctions
				if(tmpDirection) junctionNode = tmpStreet.getEndNode();
				else junctionNode = tmpStreet.getStartNode();
				if(junctionNode.getJunction() != null){
	
					if(junctionAllowed_ != junctionNode){
						if(routeDirections_[i+1]) nextNode = routeStreets_[i+1].getEndNode();
						else nextNode = routeStreets_[i+1].getStartNode();
						if(junctionNode.isHasTrafficSignal_()){
							if(junctionNode.getJunction().canPassTrafficLight(this, tmpStreet, nextNode)){	
								junctionAllowed_ = junctionNode;
								gotJunctionPermission = true;
							}
							else {
								waitingForSignal_ = true;
								return 2;
							}
						}
						else{
							int priority;
							if(tmpDirection) priority = junctionNode.getJunction().getJunctionPriority(tmpStreet.getStartNode(), nextNode);
							else priority = junctionNode.getJunction().getJunctionPriority(tmpStreet.getEndNode(), nextNode);
							if(priority != 1){	// don't do anything on priority streets
								// don't turn off faster than about 35km/h
								if(curSpeed_ > 1000){
									return 2;
								} else if(priority > 2){
									junctionNode.getJunction().addWaitingVehicle(this, priority);
									if(!emergencyVehicle_ && !fakingMessages_ && !junctionNode.getJunction().canPassJunction(this, priority, nextNode)) return 2;
									else {
										junctionAllowed_ = junctionNode;
										gotJunctionPermission = true;
									}
								}
							}
						}
					}
				}
				//get next street
				++i;
				tmpDirection = routeDirections_[i];
				tmpStreet = routeStreets_[i];
				if(tmpLane > tmpStreet.getLanesCount()) tmpLane = tmpStreet.getLanesCount();

				// Check if next street has smaller speed limit
				if(tmpStreet.getSpeed() < curSpeed_) {
					if(gotJunctionPermission) {
						junctionAllowed_.getJunction().allowOtherVehicle();
						junctionAllowed_ = null;
					}					
					return 2;
				}

				// Check if first lane object of next street on our lane forces us to stop
				if(!foundNextVehicle){
					tmpLaneObject = tmpStreet.getFirstLaneObject(tmpDirection);
					while(tmpLaneObject != null){
						if(tmpLaneObject.getCurLane() == tmpLane){
							foundNextVehicle = true;
							if((tmpDirection && tmpLaneObject.getCurPosition()+distance < curBrakingDistance_) || (!tmpDirection && tmpStreet.getLength()-tmpLaneObject.getCurPosition()+distance < curBrakingDistance_)){
								if(curSpeed_ > tmpLaneObject.getCurSpeed()-brakingRate_){
									if(gotJunctionPermission) {
										junctionAllowed_.getJunction().allowOtherVehicle();
										junctionAllowed_ = null;
									}	
									return 1;
								}
							}
							break;
						}
						tmpLaneObject = tmpLaneObject.getNext();
					}
				}

				// calculate distance of the whole street.
				distance += tmpStreet.getLength();
				// We can stop processing the next one if we get longer than braking distance
				if(distance > curBrakingDistance_) break;
				if(tmpStreet == destinations_.peekFirst().getStreet()) break;

			}		
		}

	
		return 0;
	}
	
	/**
	 * Check if a lane is free. It is considered as free if
	 * <ul><li>in front of this vehicle there's minimum double the current braking distance space and</li>
	 * <li>behind there's at least the current braking distance + 10m space</li>
	 * </ul>
	 * 
	 * @param lane 	the lane to check
	 * 
	 * @return <code>true</code> if lane is free, else <code>false</code>
	 */
	
	private final boolean checkLaneFree(int lane){
		// ================================= 
		// Step 1: Check space in front
		// ================================= 
		boolean foundNextVehicle = false;
		int neededFreeDistance = curBrakingDistance_ / 2;
		// check the lane object in front of us (on our street)
		if(next_ != null){
			if(next_.getCurLane() == lane){	// next one is on the same lane
				foundNextVehicle = true;
				if((curDirection_ && next_.getCurPosition()-curPosition_ < neededFreeDistance) || (!curDirection_ && curPosition_-next_.getCurPosition() < neededFreeDistance)){
					if(curSpeed_ > next_.getCurSpeed()-brakingRate_) return false;
				}
			} else {	// need to search for the next which is on our lane
				LaneObject tmpLaneObject = next_.getNext();
				while(tmpLaneObject != null){
					if(tmpLaneObject.getCurLane() == lane){
						foundNextVehicle = true;
						if((curDirection_ && tmpLaneObject.getCurPosition()-curPosition_ < neededFreeDistance) || (!curDirection_ && curPosition_-tmpLaneObject.getCurPosition() < neededFreeDistance)){
							if(curSpeed_ > next_.getCurSpeed()-brakingRate_) return false;
						}
						break;	// only check the first on our lane!
					}
					tmpLaneObject = tmpLaneObject.getNext();
				}
			}
		}
		double distance;
		if(curDirection_) distance = curStreet_.getLength() - curPosition_;
		else distance = curPosition_;
		// only do the big calculation if the current street is empty AND the remainder of the current street is shorter than the braking distance
		if(!foundNextVehicle && distance < neededFreeDistance){
			Street tmpStreet = curStreet_;
			LaneObject tmpLaneObject;
			boolean tmpDirection = curDirection_;
			// check next streets that we will visit. If routing is empty this automatically skips (which is what we actually want)
			for(int i = routePosition_ + 1; i < routeStreets_.length; ++i){
				tmpDirection = routeDirections_[i];
				tmpStreet = routeStreets_[i];		

				if(!foundNextVehicle){
					tmpLaneObject = tmpStreet.getFirstLaneObject(tmpDirection);
					while(tmpLaneObject != null){
						if(tmpLaneObject.getCurLane() == lane){
							foundNextVehicle = true;
							if((tmpDirection && tmpLaneObject.getCurPosition()+distance < neededFreeDistance) || (!tmpDirection && tmpStreet.getLength()-tmpLaneObject.getCurPosition()+distance < neededFreeDistance)){
								if(curSpeed_ > tmpLaneObject.getCurSpeed()-brakingRate_) return false;
							}
							break;
						}
						tmpLaneObject = tmpLaneObject.getNext();
					}
				}

				// calculate distance of the whole street. We can stop processing the next one if we get longer than braking distance
				distance += tmpStreet.getLength();
				if(distance > neededFreeDistance) break;
			}
		}

		// ================================= 
		// Step 2: Check space behind
		// ================================= 
		neededFreeDistance = curBrakingDistance_;
		//neededFreeDistance = curBrakingDistance_ + 1000;
		boolean foundPreviousVehicle = false;
		// check the lane object before us (on our street)
		if(previous_ != null){
			if(previous_.getCurLane() == lane){	// is on the same lane
				foundPreviousVehicle = true;
				if((curDirection_ && curPosition_-previous_.getCurPosition() < neededFreeDistance) || (!curDirection_ && previous_.getCurPosition()-curPosition_ < neededFreeDistance)){
					if(curSpeed_ > previous_.getCurSpeed()-brakingRate_) return false;
				}
			} else {	// need to search for the previous one which is on our lane
				LaneObject tmpLaneObject = previous_.getPrevious();
				while(tmpLaneObject != null){
					if(tmpLaneObject.getCurLane() == lane){
						foundPreviousVehicle = true;
						if((curDirection_ && curPosition_-tmpLaneObject.getCurPosition() < neededFreeDistance) || (!curDirection_ && tmpLaneObject.getCurPosition()-curPosition_ < neededFreeDistance)){
							if(curSpeed_ > previous_.getCurSpeed()-brakingRate_) return false;
						}
						break;	// only check the first on our lane!
					}
					tmpLaneObject = tmpLaneObject.getPrevious();
				}
			}
		}
		if(curDirection_) distance = curPosition_;
		else distance = curStreet_.getLength() - curPosition_;
		// current street is not long enough. need to iterate backwards
		if(!foundPreviousVehicle && distance < neededFreeDistance){
			Street[] outgoingStreets;
			Street tmpStreet = curStreet_, tmpStreet2;
			LaneObject tmpLaneObject;
			Node nextNode = null;
			boolean tmpDirection = curDirection_;
			int i;
			// check previous streets. We can't use the routing here so it's limited to streets with no junctions which makes it a bit simpler.
			while(true){
				if(tmpDirection) nextNode = tmpStreet.getStartNode();
				else nextNode = tmpStreet.getEndNode();
				if(nextNode.getCrossingStreetsCount() != 2) return false;		// don't handle junctions!
				else outgoingStreets = nextNode.getCrossingStreets();
				for(i = 0; i < outgoingStreets.length; ++i){
					tmpStreet2 = outgoingStreets[i];
					if(tmpStreet2 != tmpStreet){
						tmpStreet = tmpStreet2;
						if(lane > tmpStreet.getLanesCount()) return false;
						if (tmpStreet2.getStartNode() == nextNode){
							tmpDirection = true;
							break;		// found street we want to => no need to look through others
						} else {
							tmpDirection = false;
							break;		// found street we want to => no need to look through others
						}
					}					
				}				

				if(!foundPreviousVehicle){
					tmpLaneObject = tmpStreet.getFirstLaneObject(tmpDirection);
					while(tmpLaneObject != null){
						if(tmpLaneObject.getCurLane() == lane){
							foundNextVehicle = true;
							if((tmpDirection && tmpStreet.getLength()-tmpLaneObject.getCurPosition()+distance < neededFreeDistance) || (!tmpDirection && tmpLaneObject.getCurPosition()+distance < neededFreeDistance)){
								if(curSpeed_ > tmpLaneObject.getCurSpeed()-brakingRate_) return false;
							}
							break;
						}
						tmpLaneObject = tmpLaneObject.getNext();
					}
				}
			
				// calculate distance of the whole street. We can stop processing the next one if we get longer than braking distance
				distance += tmpStreet.getLength();
				if(distance > neededFreeDistance) break;
			}
		}
		return true;
	}
	
	
	/**
	 * Find vehicles in neighborhood and give information to them. Please check the following conditions before calling this function:
	 * <ul>
	 * <li>communication is generally enabled</li>
	 * <li>if this vehicle is active</li>
	 * <li>if it has wifi</li> 
	 * <li>if the communication countdown is 0 or less</li>
	 * </ul>
	 */
	public void sendMessages(){
	
		//clean up old penalties 		
		//ArrayList<BlockingObject> tmpO = new ArrayList<BlockingObject>(tmpBlockings);
		//for(BlockingObject o:tmpO) if(o.removeFromLane(this, Renderer.getInstance().getTimePassed())) tmpBlockings.remove(o);
				
		communicationCountdown_ += communicationInterval_;
		if(beaconsEnabled_ && !isInMixZone_){
			Message[] messages = knownMessages_.getForwardMessages();
			int size = knownMessages_.getSize();
			Vehicle nearestVehicle;
			
			//send messages to all knownRSUs
			RSU nearestRSU;
			for(int i = size - 1; i > -1; --i){			
				KnownRSU[] rsuHeads = knownRSUsList_.getFirstKnownRSU();
				int sendCount = 0;
				KnownRSU rsuNext;
				long dx, dy, maxCommSquared = (long)maxCommDistance_ * maxCommDistance_;
				for(int j = 0; j < rsuHeads.length; ++j){
					rsuNext = rsuHeads[j];								
					while(rsuNext != null){
						++sendCount;
						nearestRSU = rsuNext.getRSU();
						dx = nearestRSU.getX() - curX_;
						dy = nearestRSU.getY() - curY_;
						if((dx * dx + dy * dy) < maxCommSquared && !nearestRSU.isEncrypted_()){	//check if vehicle really is in communication distance and it's no mix-zone rsu
							nearestRSU.receiveMessage(curX_, curY_, messages[i]);
						}
						rsuNext = rsuNext.getNext();
					}
				}
				
				// flooding mode => send to all known vehicles
				if(messages[i].getFloodingMode()){
					KnownVehicle[] heads = knownVehiclesList_.getFirstKnownVehicle();
					KnownVehicle next;
					for(int j = 0; j < heads.length; ++j){
						next = heads[j];								
						while(next != null){
							++sendCount;
							nearestVehicle = next.getVehicle();
							dx = nearestVehicle.getX() - curX_;
							dy = nearestVehicle.getY() - curY_;
							if((dx * dx + dy * dy) < maxCommSquared){	//check if vehicle really is in communication distance
								//nearestVehicle.setColor(Color.red);
								nearestVehicle.receiveMessage(curX_, curY_, messages[i]);
							}
							next = next.getNext();
						}
					}

					if(sendCount > 0) knownMessages_.deleteForwardMessage(i, true);
				// line based mode => only communicate with the nearest known vehicle to message destination
				} else {
					
					nearestVehicle = knownVehiclesList_.findNearestVehicle(curX_, curY_, messages[i].getDestinationX_(), messages[i].getDestinationY_(), maxCommDistance_);
					if(nearestVehicle != null){	// only communicate if a nearer vehicle was found!
						nearestVehicle.receiveMessage(curX_, curY_, messages[i]);
						//nearestVehicle.setColor(Color.green);
						knownMessages_.deleteForwardMessage(i, true);
					}
				}
			}
		} else if (!isInMixZone_ || mixZonesFallbackEnabled_){	
			Message[] messages = knownMessages_.getForwardMessages();
			int messageSize = knownMessages_.getSize();
			if(messageSize > 0){
				// only look through all vehicles if beacons are generally disabled and messages need to be sent in a bruteforce-mode or if the fallback mode in mix zones is enabled
				int MapMinX, MapMinY, MapMaxX, MapMaxY, RegionMinX, RegionMinY, RegionMaxX, RegionMaxY;
	
				// Minimum x coordinate to be considered for communication
				long tmp = curX_ - maxCommDistance_;
				if (tmp < 0) MapMinX = 0;	// Map stores only positive coordinates
				else if(tmp < Integer.MAX_VALUE) MapMinX = (int) tmp;
				else MapMinX = Integer.MAX_VALUE;
	
				// Maximum x coordinate to be considered for communication
				tmp = curX_ + (long)maxCommDistance_;
				if (tmp < 0) MapMaxX = 0;
				else if(tmp < Integer.MAX_VALUE) MapMaxX = (int) tmp;
				else MapMaxX = Integer.MAX_VALUE;
	
				// Minimum y coordinate to be considered for communication
				tmp = curY_ - maxCommDistance_;
				if (tmp < 0) MapMinY = 0;
				else if(tmp < Integer.MAX_VALUE) MapMinY = (int) tmp;
				else MapMinY = Integer.MAX_VALUE;
	
				// Maximum y coordinate to be considered for communication
				tmp = curY_ + (long)maxCommDistance_;
				if (tmp < 0) MapMaxY = 0;
				else if(tmp < Integer.MAX_VALUE) MapMaxY = (int) tmp;
				else MapMaxY = Integer.MAX_VALUE;
	
				// Get the regions to be considered for communication
				Region tmpregion = MAP.getRegionOfPoint(MapMinX, MapMinY);
				RegionMinX = tmpregion.getX();
				RegionMinY = tmpregion.getY();
	
				tmpregion = MAP.getRegionOfPoint(MapMaxX, MapMaxY);
				RegionMaxX = tmpregion.getX();
				RegionMaxY = tmpregion.getY();
				long maxCommDistance_square = (long)maxCommDistance_ * maxCommDistance_;
				long dx, dy, distance = 0;
				int i, j, k, l, size;
				Vehicle[] vehicles = null;
				Vehicle vehicle = null;
				
				RSU[] rsus = null;
				RSU rsu = null;
				
	
				// only iterate through those regions which are within the distance
				for(i = RegionMinX; i <= RegionMaxX; ++i){
					for(j = RegionMinY; j <= RegionMaxY; ++j){
						//send to vehicles
						vehicles = regions_[i][j].getVehicleArray();	//use the array as it's MUCH faster!
						size = vehicles.length;
						for(k = 0; k < size; ++k){
							vehicle = vehicles[k];
							// precheck if the vehicle is near enough and valid (check is not exact as its a rectangular box and not circle)
							if(vehicle.isWiFiEnabled() && vehicle.isActive() && vehicle != this && vehicle.getX() >= MapMinX && vehicle.getX() <= MapMaxX && vehicle.getY() >= MapMinY && vehicle.getY() <= MapMaxY){
								dx = vehicle.getX() - curX_;
								dy = vehicle.getY() - curY_;
								distance = dx * dx + dy * dy; 	// Pythagorean theorem: a^2 + b^2 = c^2 but without the needed Math.sqrt to save a little bit performance
								if(distance <= maxCommDistance_square){
									if(!isInMixZone_ || !mixZonesFallbackFloodingOnly_){
										for(l = 0; l < messageSize; ++l){
											vehicle.receiveMessage(curX_, curY_, messages[l]);
											//vehicle.setColor(Color.blue);
										}
									} else {
										for(l = 0; l < messageSize; ++l){
											if(messages[l].getFloodingMode()) {
												vehicle.receiveMessage(curX_, curY_, messages[l]);
												//vehicle.setColor(Color.cyan);
											}
										}
									}
								}
							}
						}
						
						//send to Road-Side-Units
						rsus = regions_[i][j].getRSUs();	//use the array as it's MUCH faster!
						size = rsus.length;
						for(k = 0; k < size; ++k){
							rsu = rsus[k];
							// precheck if the rsu is near enough and valid (check is not exact as its a rectangular box and not circle)
							if(rsu.getX() >= MapMinX && rsu.getX() <= MapMaxX && rsu.getY() >= MapMinY && rsu.getY() <= MapMaxY){
								dx = rsu.getX() - curX_;
								dy = rsu.getY() - curY_;
								distance = dx * dx + dy * dy; 	// Pythagorean theorem: a^2 + b^2 = c^2 but without the needed Math.sqrt to save a little bit performance
								if(distance <= maxCommDistance_square){
									if(!isInMixZone_ || !mixZonesFallbackFloodingOnly_){
										for(l = 0; l < messageSize; ++l){
											rsu.receiveMessage(curX_, curY_, messages[l]);
										}
									} else {
										for(l = 0; l < messageSize; ++l){
											if(messages[l].getFloodingMode()) rsu.receiveMessage(curX_, curY_, messages[l]);
										}
									}
								}
							}
						}
					}
				}
				if(!isInMixZone_ || !mixZonesFallbackFloodingOnly_) knownMessages_.deleteAllForwardMessages(true);
				else knownMessages_.deleteAllFloodingForwardMessages(true);
			}
		} 
	}
	
	/**
	 * Receive a message from another vehicle.
	 * 
	 * @param sourceX	the x coordinate of the other vehicle
	 * @param sourceY	the y coordinate of the other vehicle
	 * @param message	the message
	 */
	public final void receiveMessage(int sourceX, int sourceY, Message message){
		long dx = message.getDestinationX_() - curX_;
		long dy = message.getDestinationY_() - curY_;
		long distanceToDestinationSquared = dx*dx + dy*dy;
		
		if(message.getFloodingMode()){	// in flooding mode, vehicles only forward messages they got if they are within the target area
			if((message.getDestinationRadiusSquared() >= distanceToDestinationSquared) && !directCommunicationMode_){
				knownMessages_.addMessage(message, true, true);
			} else knownMessages_.addMessage(message, true, false);
		} else {	// line-based mode
			if(message.getDestinationRadiusSquared() >= distanceToDestinationSquared){
				message.setFloodingMode(true);	// enable flooding mode if within distance!
			}
			if(beaconsEnabled_){	// if beacons are enabled, we can be sure that we are nearer than the last vehicle
				if(directCommunicationMode_)knownMessages_.addMessage(message, true, false);
				else knownMessages_.addMessage(message, true, true);
			} else {
				// no beacons. check manually if we are nearer to the destination than the sending vehicle
				dx = message.getDestinationX_() - sourceX;
				dy = message.getDestinationY_() - sourceY;
				if(((dx * dx + dy * dy) > distanceToDestinationSquared)  && !directCommunicationMode_){
					knownMessages_.addMessage(message, true, true);
				} else knownMessages_.addMessage(message, true, false);
			}
		}
	}

	/**
	 * Find vehicles in neighborhood and send beacons to them. Please check the following conditions before calling this function:
	 * <ul>
	 * <li>communication is generally enabled</li>
	 * <li>beacons are generally enabled</li>
	 * <li>if this vehicle is active</li>
	 * <li>if it has wifi</li> 
	 * <li>if the beacon countdown is 0 or less</li>
	 * <li>if vehicle is not in a mix zone</li>
	 * </ul>
	 */
	public void sendBeacons(){
		beaconCountdown_ += beaconInterval_;
		
			
		if(isInSlow && !changedPseudonymInSlow && Renderer.getInstance().getTimePassed() >= (slowTimestamp + TIME_TO_PSEUDONYM_CHANGE - (2*beaconInterval_))){
			changedPseudonymInSlow = true;
			
			++IDsChanged_;
			ID_ = ownRandom_.nextLong();
		}
		
		if(slowOn){
			if(privacyDataLogged_ && isInSlow && !slowBeaconsLogged){
				slowBeaconsLogged = true;
				if(!vehicleJustStartedInSlow)PrivacyLogWriter.log(savedBeacon2.replace("%0%aa%0%", "IN")  + "\n" + savedBeacon1.replace("%0%aa%0%", "IN") );
			}
			
			else if(privacyDataLogged_ && !isInSlow && slowBeaconsLogged){
				slowBeaconsLogged = false;
				
				logNextBeacons = 2;
			}
		}
		/*
		if(((Renderer.getInstance().getTimePassed() - slowTimestamp) > 60000) && !vehicleCounted){
			vehicleCounted = true;
			vehiclesInSlow++;
		}
		if(Renderer.getInstance().getTimePassed()%24000 == 0)System.out.println(vehiclesInSlow);
		*/
		if(slowOn){
			if(!isInSlow && this.curSpeed_ <= SLOW_SPEED_LIMIT && logNextBeacons == 0){
				isInSlow = true;
				slowTimestamp = Renderer.getInstance().getTimePassed();
				changedPseudonymInSlow = false;

			}
			else if(isInSlow && this.curSpeed_ > SLOW_SPEED_LIMIT && (Renderer.getInstance().getTimePassed() - slowTimestamp) > (2*beaconInterval_)){
				isInSlow = false;
			}
		}


		
		if(silent_period != silentPeriod){ 
			silentPeriod = silent_period;
			
			if(!silent_period) logNextBeacons = 2;
			//log beacon
			if(silentPeriod && privacyDataLogged_ && isSilentPeriodsOn()) PrivacyLogWriter.log(savedBeacon2 + "\n" + savedBeacon1);
		}
		

		
		if(!silent_period && !isInSlow){
			//beaconCountdown_ += beaconInterval_;
			int i, j, k, size = 0, MapMinX, MapMinY, MapMaxX, MapMaxY, RegionMinX, RegionMinY, RegionMaxX, RegionMaxY;
			Vehicle[] vehicles = null;
			Vehicle vehicle = null;
		

			// Minimum x coordinate to be considered for sending beacons
			long tmp = curX_ - maxCommDistance_;
			if (tmp < 0) MapMinX = 0;	// Map stores only positive coordinates
			else if(tmp < Integer.MAX_VALUE) MapMinX = (int) tmp;
			else MapMinX = Integer.MAX_VALUE;

			// Maximum x coordinate to be considered for sending beacons
			tmp = curX_ + (long)maxCommDistance_;
			if (tmp < 0) MapMaxX = 0;
			else if(tmp < Integer.MAX_VALUE) MapMaxX = (int) tmp;
			else MapMaxX = Integer.MAX_VALUE;

			// Minimum y coordinate to be considered for sending beacons
			tmp = curY_ - maxCommDistance_;
			if (tmp < 0) MapMinY = 0;
			else if(tmp < Integer.MAX_VALUE) MapMinY = (int) tmp;
			else MapMinY = Integer.MAX_VALUE;

			// Maximum y coordinate to be considered for sending beacons
			tmp = curY_ + (long)maxCommDistance_;
			if (tmp < 0) MapMaxY = 0;
			else if(tmp < Integer.MAX_VALUE) MapMaxY = (int) tmp;
			else MapMaxY = Integer.MAX_VALUE;

			// Get the regions to be considered for sending beacons
			Region tmpregion = MAP.getRegionOfPoint(MapMinX, MapMinY);
			RegionMinX = tmpregion.getX();
			RegionMinY = tmpregion.getY();

			tmpregion = MAP.getRegionOfPoint(MapMaxX, MapMaxY);
			RegionMaxX = tmpregion.getX();
			RegionMaxY = tmpregion.getY();
			long maxCommDistanceSquared = (long)maxCommDistance_ * maxCommDistance_;
			long dx, dy;


			// only iterate through those regions which are within the distance
			for(i = RegionMinX; i <= RegionMaxX; ++i){
				for(j = RegionMinY; j <= RegionMaxY; ++j){
					vehicles = regions_[i][j].getVehicleArray();	//use the array as it's MUCH faster!
					size = vehicles.length;

					for(k = 0; k < size; ++k){
						vehicle = vehicles[k];
						// precheck if the vehicle is near enough and valid (check is not exact as its a rectangular box and not circle)
						if(vehicle.isWiFiEnabled() && vehicle.isActive() && vehicle != this && vehicle.getX() >= MapMinX && vehicle.getX() <= MapMaxX && vehicle.getY() >= MapMinY && vehicle.getY() <= MapMaxY){
							dx = vehicle.getX() - curX_;
							dy = vehicle.getY() - curY_;
							if((dx * dx + dy * dy) <= maxCommDistanceSquared){	// Pythagorean theorem: a^2 + b^2 = c^2 but without the needed Math.sqrt to save a little bit performance
								if(emergencyBeacons > 0){
									vehicle.getIdsProcessorList_().updateProcessor((ID_-1), curX_, curY_, curSpeed_, curLane_);
									vehicle.getKnownVehiclesList().updateVehicle(this, (ID_-1), curX_, curY_, curSpeed_, vehicle.getID(), false,false);
								}
								else if (emergencyBeacons == 0){
									//fake messages
									
									// find the destination for the message. Will be sent to the next junction behind us! (if its pcn we send it in front)
									boolean tmpDirection2 = curDirection_;
										
									Street tmpStreet2 = curStreet_;
									Street[] crossingStreets;
									Node tmpNode;
									int k1, l = 0, destX = -1, destY = -1;
									do{
										++l;
										if(tmpDirection2){
											tmpNode = tmpStreet2.getStartNode();
										} else {
											tmpNode = tmpStreet2.getEndNode();
										}
										if(tmpNode.getJunction() != null){
											destX = tmpNode.getX();
											destY = tmpNode.getY();
											break;
										}
										crossingStreets = tmpNode.getCrossingStreets();
										// find next street behind of us
										if(crossingStreets.length != 2){	// end of a street or some special case. don't forward any further
											destX = tmpNode.getX();
											destY = tmpNode.getY();
											break;
										}
										for(k1 = 0; k1 < crossingStreets.length; ++k1){
											if(crossingStreets[k1] != tmpStreet2){
												tmpStreet2 = crossingStreets[k1];
												if(tmpStreet2.getStartNode() == tmpNode) tmpDirection2 = false;
												else tmpDirection2 = true;
												break;
											}
										}
									} while(tmpStreet2 != curStreet_ && l < 10000);	//hard limit of 10000 nodes to maximally go back or if again arriving at source street (=>circle!)
									// found destination...now insert into messagequeue
									if(destX != -1 && destY != -1){
										int direction = -1;
										//if(!curDirection_) direction = 1;
										int time = Renderer.getInstance().getTimePassed();
										
										PenaltyMessage message = new PenaltyMessage(curX_, curY_, destX, destY, PENALTY_FAKE_MESSAGE_RADIUS, time + PENALTY_MESSAGE_VALID, curStreet_, curLane_, direction, PENALTY_MESSAGE_VALUE, time + PENALTY_VALID, true, (ID_-1), this,  "EVA_EMERGENCY_ID", true, true);
										message.setFloodingMode(true);	// enable flooding mode if within distance!				
										knownMessages_.addMessage(message, false, true);	
										
										emergencyBeacons = -1;								
									}		
									++fakeMessagesCreated_;
									
									fakeMessageCounter_ = fakeMessageCounter_%fakeMessageTypesCount;
								}
								
								
									
							
								
								vehicle.getKnownVehiclesList().updateVehicle(this, ID_, curX_, curY_, curSpeed_, vehicle.getID(), false,false);
								vehicle.getIdsProcessorList_().updateProcessor(ID_, curX_, curY_, curSpeed_, curLane_);
							}
						}
					}
				}
			}
 
			if(emergencyBeacons >= 0) emergencyBeacons--;
				/*
				if(emergencyBeacons == 0){
					PenaltyMessage message = new PenaltyMessage(curX_, curY_, destX, destY, PENALTY_FAKE_MESSAGE_RADIUS, time + PENALTY_MESSAGE_VALID, curStreet_, curLane_, direction, PENALTY_MESSAGE_VALUE, time + PENALTY_VALID, true, ID_, this,  messageType, true, true);
					message.setFloodingMode(false);	// enable flooding mode if within distance!				
					knownMessages_.addMessage(message, true, true);
				}
				
			}
			*/
			// allow beacon monitoring
			if(beaconMonitorEnabled_){
				if(curX_ >= beaconMonitorMinX_ && curX_ <= beaconMonitorMaxX_ && curY_ >= beaconMonitorMinY_ && curY_ <= beaconMonitorMaxY_){
					REPORT_PANEL.addBeacon(this, ID_, curX_, curY_, curSpeed_, false);
				}
			}
				
			GeneralLogWriter.log(ID_ + ":" + curX_ + ":" +  curY_ + ":" +  curSpeed_); 
			
			
			if(logBeaconsAfterEvent_){
				amountOfLoggedBeacons_++;
				if(amountOfLoggedBeacons_ == 10){
					beaconString_ += "," + curX_ + "," + curY_ + "," + curSpeed_;
					if(!beaconString_.equals(","))GeneralLogWriter.log(beaconString_); 
					logBeaconsAfterEvent_ = false;
				}
				else{
					beaconString_ += "," + curX_ + "," + curY_ + "," + curSpeed_;
				}
			}
			
			// interception of Beacons by ARSUs
			AttackRSU[] tempARSUList = getArsuList();
			if(tempARSUList.length>0){
			    for(int l = 0; l < tempARSUList.length;l++) {
			    	dx = tempARSUList[l].getX() - curX_;
			    	dy = tempARSUList[l].getY() - curY_;
			    	
			   
					if((dx * dx + dy * dy) <= maxCommDistanceSquared){	// Pythagorean theorem: a^2 + b^2 = c^2 but without the needed Math.sqrt to save a little bit performance
						if(Renderer.getInstance().getAttackerVehicle() != null && !Renderer.getInstance().getAttackerVehicle().equals(this))Renderer.getInstance().getAttackerVehicle().getKnownVehiclesList().updateVehicle(this, ID_, curX_, curY_, curSpeed_, tempARSUList[l].getArsuID_(), false, true);
					}	    	
			      }

			}

			if(privacyDataLogged_ && (silentPeriodsOn || slowOn)){				
				savedBeacon2 = savedBeacon1;
				savedBeacon1 = Renderer.getInstance().getTimePassed() + ":Steady ID:" + this.steadyID_ + ":Pseudonym:" + Long.toHexString(this.ID_) + ":TraveledDistance:" + totalTravelDistance_ + ":TraveledTime:" + totalTravelTime_ + ":Node ID:None" + ":Direction:%0%aa%0%" + ":Street:" + this.getCurStreet().getName() + ":StreetSpeed:" + this.getCurStreet().getSpeed() + ":VehicleSpeed:" + this.getCurSpeed() +  ":x:" + this.curX_ + ":y:" + this.curY_;
			
				if(logNextBeacons == 1){
					logNextBeacons = 0;
					if(!slowOn || !vehicleJustStartedInSlow)PrivacyLogWriter.log(savedBeacon2.replace("%0%aa%0%", "OUT") + ":TimeInSlow:" +  (Renderer.getInstance().getTimePassed() - slowTimestamp) + "\n" + savedBeacon1.replace("%0%aa%0%", "OUT"));
					if(vehicleJustStartedInSlow) vehicleJustStartedInSlow = false;
				}
				else if(logNextBeacons == 2){
					logNextBeacons--;
				}
			}
		}
	}
	
	/**
	 * Find vehicles nearest in neighborhood and send encrypted beacons to them. Please check the following conditions before calling this function:
	 * <ul>
	 * <li>communication is generally enabled</li>
	 * <li>beacons are generally enabled</li>
	 * <li>if this vehicle is active</li>
	 * <li>if it has wifi</li> 
	 * <li>if the beacon countdown is 0 or less</li>
	 * <li>if vehicle is in a mix zone</li>
	 * <li>if encryptedBeaconsInMix is enabled</li>
	 * </ul>
	 */
	public void sendEncryptedBeacons(){
		if(!silentPeriod){
			beaconCountdown_ += beaconInterval_;
			
			RSU tmpRSU = null;

			if(curMixNode_.getEncryptedRSU_() != null){
				tmpRSU = curMixNode_.getEncryptedRSU_();
				tmpRSU.getKnownVehiclesList_().updateVehicle(this, ID_, curX_, curY_, curSpeed_, tmpRSU.getRSUID(), true, false);

				// allow beacon monitoring
				if(beaconMonitorEnabled_){
					if(curX_ >= beaconMonitorMinX_ && curX_ <= beaconMonitorMaxX_ && curY_ >= beaconMonitorMinY_ && curY_ <= beaconMonitorMaxY_){
						REPORT_PANEL.addBeacon(this, ID_, curX_, curY_, curSpeed_, true);
					}
				}

			}	
		}
		
		//check if the static flag is the same as the object flag. If not a silent period is beginning or ending -> log
		if(silent_period != silentPeriod){ 
			silentPeriod = silent_period;
			
			//silent period did begin -> log
			if(silentPeriod){
				if(privacyDataLogged_) PrivacyLogWriter.log(Renderer.getInstance().getTimePassed() + ":Steady ID:" + this.steadyID_ + ":Pseudonym:" + Long.toHexString(this.ID_) + ":TraveledDistance:" + totalTravelDistance_ + ":TraveledTime:" + totalTravelTime_ + ":Node ID:none" + ":Direction:IN" +  ":x:" + this.curX_ + ":y:" + this.curY_);
			}
			//silent perdiod did end -> log and change pseudonym
			else{
				ID_ = ownRandom_.nextLong();
				if(privacyDataLogged_) PrivacyLogWriter.log(Renderer.getInstance().getTimePassed() + ":Steady ID:" + this.steadyID_ + ":Pseudonym:" + Long.toHexString(this.ID_) + ":TraveledDistance:" + totalTravelDistance_ + ":TraveledTime:" + totalTravelTime_ + ":Node ID:none" + ":Direction:OUT" +  ":x:" + this.curX_ + ":y:" + this.curY_);
			}
		}
	}

	/**
	 * Move the vehicle one step forward. Please check if the vehicle is active before calling this!
	 * 
	 * @param timePerStep	the time per step in milliseconds
	 */
	public void move(int timePerStep){
		if(curWaitTime_ == 0 && curStreet_ != null){

			curLane_ = newLane_;
			curSpeed_ = newSpeed_;

			// ================================= 
			// Step 1: Move the vehicle according to its speed
			// ================================= 
			double tmpPosition, newPosition = curPosition_, movement;
			WayPoint nextTarget;
			movement = curSpeed_ * (timePerStep/1000.0);
			totalTravelTime_ += timePerStep;
			totalTravelDistance_ += movement;	// not totally precise when reaching destination but should be enough as long as timePerStep is less than a second...
			Street oldStreet = curStreet_;
			boolean oldDirection = curDirection_;
			while(movement > 0){
				if(curDirection_) tmpPosition = newPosition + movement;
				else tmpPosition = newPosition - movement;
				// no more routing points and on the street specified by the waypoint
				if(routePosition_ == routeStreets_.length-1 && destinations_.peekFirst().getStreet() == curStreet_){
					nextTarget = destinations_.peekFirst();	//doing this intentionally after the if! The peekFirst() is performed twice but in almost always the first one isn't even reached!
					if((curDirection_ && nextTarget.getPositionOnStreet() < tmpPosition) || (!curDirection_ && nextTarget.getPositionOnStreet() > tmpPosition)){		// gone over the position specified by the waypoint
						//we're on the last street of a routing but we still got more waypoints
						movement = tmpPosition - nextTarget.getPositionOnStreet();
						newPosition = nextTarget.getPositionOnStreet();
						do{
							destinations_.poll();
							if(destinations_.isEmpty()) break;
							curWaitTime_ = destinations_.peekFirst().getWaittime();
						} while(!calculateRoute(true, false));
						if(destinations_.isEmpty()){
							//if logging and slow is active write in privacy log to flag that the last slow won't be counted
							if(slowOn)PrivacyLogWriter.log("VehicleReachedDestination:" + this.steadyID_ + ":" + Long.toHexString(this.ID_));
							
							active_ = false;	//found no new destination where we can route to
							curWaitTime_ = Integer.MIN_VALUE;
							if(totalTravelTime_ >= minTravelTimeForRecycling_) mayBeRecycled_ = true;
							break;	
						} else brakeForDestinationCountdown_ = Integer.MAX_VALUE;
						if(curWaitTime_ > 0){
							curSpeed_ = 0;
							break;		//movement to next destination shall begin after some waiting on the current location
						} else brakeForDestination_ = false;		//stop braking for destination
					} else {
						newPosition = tmpPosition;
						movement = 0;
					}
				// leaving current street as movement is larger than the street length!
				} else if((curDirection_ && tmpPosition > curStreet_.getLength()) || (!curDirection_ && tmpPosition < 0)){
					if(curDirection_) movement = tmpPosition - curStreet_.getLength();
					else movement = -tmpPosition;
					++routePosition_;
					if(routePosition_ >= routeStreets_.length){	//no more routing entries
						//create a correct last position if routing to a next waypoint fails later
						if(curDirection_) newPosition = curStreet_.getLength();
						else newPosition = 0;
						do{
							destinations_.poll();
							if(destinations_.isEmpty()) break;
							curWaitTime_ = destinations_.peekFirst().getWaittime();
						} while(!calculateRoute(true, false));
						if(destinations_.isEmpty()){
							active_ = false;	//found no new destination where we can route to
							curWaitTime_ = Integer.MIN_VALUE;
							if(totalTravelTime_ >= minTravelTimeForRecycling_) mayBeRecycled_ = true;
							break;	
						} else brakeForDestinationCountdown_ = Integer.MAX_VALUE;
						if(curWaitTime_ > 0){
							curSpeed_ = 0;
							break;		//movement to next destination shall begin after some waiting on the current location
						} else brakeForDestination_ = false;	//stop braking for destination
					} 
					curDirection_ = routeDirections_[routePosition_];
					/*
					//use this to log vehicles passing junctions. To count the different routes and their frequency.
					Node tmpNode = null;
					int street1 = -1;
					int street2 = -1;
 					if(curDirection_ && routeStreets_[routePosition_].getStartNode().getCrossingStreetsCount() > 2){
 						tmpNode = routeStreets_[routePosition_].getStartNode();
 						for(int b = 0; b < tmpNode.getCrossingStreetsCount(); b++){
 							if(tmpNode.getCrossingStreets()[b].equals(curStreet_)) street1 = b;
 							if(tmpNode.getCrossingStreets()[b].equals(routeStreets_[routePosition_])) street2 = b;
 						}
 						GeneralLogWriter.log(tmpNode.getNodeID() + ":" + street1 + ":" + street2);
					}
					else if(!curDirection_ && routeStreets_[routePosition_].getEndNode().getCrossingStreetsCount() > 2) {
						tmpNode = routeStreets_[routePosition_].getEndNode();
 						for(int b = 0; b < tmpNode.getCrossingStreetsCount(); b++){
 							if(tmpNode.getCrossingStreets()[b].equals(curStreet_)) street1 = b;
 							if(tmpNode.getCrossingStreets()[b].equals(routeStreets_[routePosition_])) street2 = b;
 						}
 						GeneralLogWriter.log(tmpNode.getNodeID() + ":" + street1 + ":" + street2);
					}

*/
					curStreet_ = routeStreets_[routePosition_];	
					
					if(curDirection_){						
						if(curStreet_.getStartNode() == junctionAllowed_){
							junctionAllowed_.getJunction().allowOtherVehicle();
							junctionAllowed_ = null;
						}
						newPosition = 0;
					} else {				
						if(curStreet_.getEndNode() == junctionAllowed_){
							junctionAllowed_.getJunction().allowOtherVehicle();
							junctionAllowed_ = null;
						}
						newPosition = curStreet_.getLength();
					}
				} else {
					newPosition = tmpPosition;
					movement = 0;
				}
			}
			if(!active_ || curWaitTime_ != 0) {
				oldStreet.delLaneObject(this, oldDirection);
				curPosition_ = newPosition;
			}
			else if(curStreet_ != oldStreet || curDirection_ != oldDirection){
				if(curStreet_.getLanesCount() < curLane_){
					curLane_ = curStreet_.getLanesCount();
					newLane_ = curLane_;
				}
				oldStreet.delLaneObject(this, oldDirection);
				curPosition_ = newPosition;
				curStreet_.addLaneObject(this, curDirection_);
			} else if (curLane_ > 1 || drivingOnTheSide_ || passingBlocking_){	// all vehicles which are on multilanes and which did not change street need to call the update method in the LaneContainer to preserve order!
				passingBlocking_ = false;
				curStreet_.updateLaneObject(this, curDirection_, newPosition);	// updates curPosition_ in the synchronized method!
			} else {
				curPosition_ = newPosition;
			}

			// ================================= 
			// Step 2: Recalculate values
			// ================================= 

			// recalculate position on map
			if(curStreet_ != null){
				calculatePosition();
			}

			// recalculate region
			if(curX_ < curRegion_.getLeftBoundary() || curX_ > curRegion_.getRightBoundary() || curY_ < curRegion_.getUpperBoundary() || curY_ > curRegion_.getLowerBoundary()){
				curRegion_.delVehicle(this);
				curRegion_ = MAP.getRegionOfPoint(curX_, curY_);
				curRegion_.addVehicle(this, false);
			}			
		}

	}

	
	/**
	 * Move Attacker. 
	 */
	public final void moveAttacker(){
		Vehicle tmpAttacked = Renderer.getInstance().getAttackedVehicle();
		//Save if attacker is in mix-zone
		if(isInMixZone_ && firstContact) attackerWasInMix = true;
		
		//If attacked vehicle drives in mix-zone set it null and save information that the attacked vehicle was in mix-zone
		if(tmpAttacked != null && tmpAttacked.isInMixZone_ && firstContact) {
			Renderer.getInstance().setAttackedVehicle(null);
			Vehicle.setAttackedVehicleID_(0);
			attackedWasInMix = true;
			newSpeed_ = curStreet_.getSpeed();
			//Make route to leave the mix-zone
			searchAttackedVehicle_();
		}
 
		//If attacker has left the mix-zone look for the attacked vehicle. Note that it is just plain guessing here.
		if(attackedWasInMix && attackerWasInMix && !isInMixZone_ && firstContact){
			if(getKnownVehiclesList().findNearestVehicle(0, 0, curX_, curY_, 10000000) != null){
				Vehicle.setAttackedVehicleID_(getKnownVehiclesList().findNearestVehicle(0, 0, curX_, curY_, 10000000).getID());
				Renderer.getInstance().setAttackedVehicle(getKnownVehiclesList().findNearestVehicle(0, 0, curX_, curY_, 10000000));
				attackedWasInMix = false;
			}
		}
		
		//Attacker knows attacked Vehicle: follow it
		if(attackedVehicleID_ != 0) {
			reRouteTime_--;
			if(reRouteTime_ < 0){
				reRouteTime_=ATTACKER_INTERVAL;
				long dx, dy, dg;
				KnownVehicle[] heads = knownVehiclesList_.getFirstKnownVehicle();
				KnownVehicle next;
				
				//traverse all vehicle which sent beacons
				for(int l = 0; l < heads.length; ++l){
					next = heads[l];								
					while(next != null){
						//Find the attacker data
						if(next.getVehicle().getID() == attackedVehicleID_){
							firstContact = true;
							
							dx = next.getVehicle().getX() - curX_;
							dy = next.getVehicle().getY() - curY_;
							dg = (dx * dx + dy * dy);
	
							//update speed if attacker is to near / to far
							if(dg > 60000000) newSpeed_ = maxSpeed_;
							else if(dg > 20000000 && dg < 60000000) newSpeed_ = Renderer.getInstance().getAttackedVehicle().getCurSpeed();
							else if(dg < 20000000) newSpeed_ = 0;
							
							//clear destinations and add new ones (only if the attacker is far enough away
							//from the attacked vehicle. Otherwise the attacker would reach the final destination
							//until it gets a new one)
							if(dg > 10000000){
							getDestinations().clear();
								try {
									getDestinations().add(new WayPoint(next.getX(),next.getY(),0));
									getDestinations().add(new WayPoint(next.getX(),next.getY(),0));
									calculateRoute(false, true);
									brakeForDestination_ = false;
									brakeForDestinationCountdown_ = 1000;
								} catch (ParseException e) {
									// TODO Auto-generated catch block
									e.printStackTrace();
								}
							}
						next = null;
						}
						else next = next.getNext();
					}
				}
			}
		}
	}


	/**
	 * The attacked vehicle can�t be found. But it can�t be far because we received a beacon the last time.
	 * This method is only evoked one time per mix-zone so it doesn't need to be that efficient
	 */
	public void searchAttackedVehicle_(){
		boolean NodeFound = false;
		Node tempNode = curStreet_.getStartNode();
		if(!curDirection_) tempNode = curStreet_.getEndNode();
		
		int guessX = curX_ - destinations_.peekFirst().getX();
		int guessY = curY_ - destinations_.peekFirst().getY();
		
		//Traverse the street nodes 
		//The vehicle try's to conserve the current vector
		for(int i = 0;i < tempNode.getCrossingStreets().length; i++){
			Node tempNode2;
			if(tempNode.equals(tempNode.getCrossingStreets()[i].getEndNode())) tempNode2 = tempNode.getCrossingStreets()[i].getStartNode();
			else tempNode2 = tempNode.getCrossingStreets()[i].getEndNode();
			
			if(guessX < 0 && guessY < 0) if(curX_ < tempNode2.getX() && curY_ < tempNode2.getY()) {
				NodeFound = true;
				tempNode = tempNode2;
				i=10;
			}
			else if(guessX < 0 && guessY > 0) if(curX_ < tempNode2.getX() && curY_ > tempNode2.getY() ) {
				NodeFound = true;
				tempNode = tempNode2;
				i=10;
			}
			else if(guessX > 0 && guessY > 0) if(curX_ > tempNode2.getX() && curY_ > tempNode2.getY() ) {
				NodeFound = true;
				tempNode = tempNode2;
				i=10;
			}
			else if(guessX > 0 && guessY < 0) if(curX_ > tempNode2.getX() && curY_ < tempNode2.getY() )  {
				NodeFound = true;
				tempNode = tempNode2;
				i=10;
			}
		}
		
		//if it can't be found (e.g. because the street changes direction) we look for a node that isn't as perfect but still works
		if(!NodeFound){
			for(int i = 0;i < tempNode.getCrossingStreets().length; i++){
				Node tempNode2;
				if(tempNode.equals(tempNode.getCrossingStreets()[i].getEndNode())) tempNode2 = tempNode.getCrossingStreets()[i].getStartNode();
				else tempNode2 = tempNode.getCrossingStreets()[i].getEndNode();
				
				if(Math.abs(guessX) > Math.abs(guessY)){
					if(guessX < 0){
						if(curX_  < tempNode2.getX()) {
							tempNode = tempNode2;
							i=10;
						}
					}
					else if(guessX > 0){
						if(curX_  > tempNode2.getX()) {
							tempNode = tempNode2;
							i=10;
						}
					}
				}
				else{
					if(guessY < 0){
						if(curY_ < tempNode2.getY()){
							tempNode = tempNode2;
							i=10;				
						}
					}
					else if(guessY > 0){
						if(curY_ > tempNode2.getY()) {
							tempNode = tempNode2;
							i=10;				
						}
					}
				}
			}
		}
		
		//we search for 30 more nodes to make sure to drive longer than the mix zone. This is not really performant but this function is only evoked on time per mix-zone
		for(int j = 0;j < 30;j++){
			NodeFound = false;

			for(int i = 0;i < tempNode.getCrossingStreets().length; i++){
				Node tempNode2;
				if(tempNode.equals(tempNode.getCrossingStreets()[i].getEndNode())) tempNode2 = tempNode.getCrossingStreets()[i].getStartNode();
				else tempNode2 = tempNode.getCrossingStreets()[i].getEndNode();
				
				if(guessX < 0 && guessY < 0) if(tempNode.getX() < tempNode2.getX() && tempNode.getY() < tempNode2.getY()) {
					NodeFound = true;
					tempNode = tempNode2;
					i=10;
				}
				else if(guessX < 0 && guessY > 0) if(tempNode.getX() < tempNode2.getX() && tempNode.getY() > tempNode2.getY() ) {
					NodeFound = true;
					tempNode = tempNode2;
					i=10;
				}
				else if(guessX > 0 && guessY > 0) if(tempNode.getX() > tempNode2.getX() && tempNode.getY() > tempNode2.getY() ) {
					NodeFound = true;
					tempNode = tempNode2;
					i=10;
				}
				else if(guessX > 0 && guessY < 0) if(tempNode.getX() > tempNode2.getX() && tempNode.getY() < tempNode2.getY() )  {
					NodeFound = true;
					tempNode = tempNode2;
					i=10;
				}
			}
			
			if(!NodeFound){
				for(int i = 0;i < tempNode.getCrossingStreets().length; i++){
					Node tempNode2;
					if(tempNode.equals(tempNode.getCrossingStreets()[i].getEndNode())) tempNode2 = tempNode.getCrossingStreets()[i].getStartNode();
					else tempNode2 = tempNode.getCrossingStreets()[i].getEndNode();
					
					if(Math.abs(guessX) > Math.abs(guessY)){
						if(guessX < 0){
							if(tempNode.getX()  < tempNode2.getX()) {
								tempNode = tempNode2;
								i=10;
							}
						}
						else if(guessX > 0){
							if(tempNode.getX()  > tempNode2.getX()) {
								tempNode = tempNode2;
								i=10;
							}
						}
					}
					else{
						if(guessY < 0){
							if(tempNode.getY() < tempNode2.getY()){
								tempNode = tempNode2;
								i=10;				
							}
						}
						else if(guessY > 0){
							if(tempNode.getY() > tempNode2.getY()) {
								tempNode = tempNode2;
								i=10;				
							}
						}
					}
				}
				}
		}

				
		//clear the old destinations and save the new ones.
		getDestinations().clear();
		try {
			getDestinations().add(new WayPoint(tempNode.getX(),tempNode.getY(),0));
			getDestinations().add(new WayPoint(tempNode.getX(),tempNode.getY(),0));
			calculateRoute(false, true);
			brakeForDestination_ = false;
			brakeForDestinationCountdown_ = 1000;
		} catch (ParseException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	/**
	 * Resets this vehicle so that it can be reused. It will travel on the same route as last time!
	 */
	public void reset(){
		//ArrayList<BlockingObject> tmpO = new ArrayList<BlockingObject>(tmpBlockings);
		//for(BlockingObject o:tmpO) tmpBlockings.remove(o);
		
		//reset countdowns and other variables
		ID_ = ownRandom_.nextLong();
		steadyID_ = steadyIDCounter++;
		curSpeed_ = brakingRate_/2;
		newSpeed_ = curSpeed_;
		totalTravelTime_ = 0;
		totalTravelDistance_ = 0;
		newLane_ = 1;
		active_ = false;
		speedAtLastBrakingDistanceCalculation_ = 0;
		isInMixZone_ = false;
		junctionAllowed_ = null;			
		brakeForDestination_ = false;
		brakeForDestinationCountdown_ = Integer.MAX_VALUE;
		destinationCheckCountdown_ = 0;
		laneChangeCountdown = 0;
		communicationCountdown_ = 0;
		knownVehiclesTimeoutCountdown_ = 0;
		knownPenaltiesTimeoutCountdown_ = 0;
		beaconCountdown_ = (int)Math.round(curPosition_)%beaconInterval_;
		communicationCountdown_ = (int)Math.round(curPosition_)%communicationInterval_;
		mixCheckCountdown_ = (int)Math.round(curPosition_)%MIX_CHECK_INTERVAL;
		emergencyBrakingCountdown_ = ownRandom_.nextInt(emergencyBrakingInterval_)+1;
	//	lastMessageCreated = 0;
		lastRHCNMessageCreated = 0;		
		lastPCNMessageCreated = 0;
		lastPCNFORWARDMessageCreated = 0;
		lastEVAMessageCreated = 0;
		//lastEVAFORWARDMessageCreated = 0;
		//lastEEBLMessageCreated = 0;
		//lastFAKEMessageCreated = 0;
		stopTime_ = 0;
		passingBlocking_ = false;
		//don't set them 0, because we wan't the count of all messages created (included the deleted ones)
		/*
		pcnMessagesCreated_ = 0;
		pcnForwardMessagesCreated_ = 0;
		evaForwardMessagesCreated_ = 0;
		evaMessagesCreated_ = 0;
		rhcnMessagesCreated_ = 0;
		eeblMessagesCreated_ = 0;
		fakeMessagesCreated_ = 0;
		*/
		IDsChanged_ = 0;
		
		//slow model
		isInSlow = false;
		changedPseudonymInSlow = false;
		slowBeaconsLogged = false;
		vehicleJustStartedInSlow = true;
		
		//reset communication info
		knownVehiclesList_.clear();
		knownPenalties_.clear();
		knownMessages_.clear();
		idsProcessorList_.clear();
		
		//reset RSU infos
		knownRSUsList_.clear();
		knownRSUsTimeoutCountdown_ = 0;
		
		speedFluctuationCountdown_ = (int)Math.round(curPosition_)%SPEED_FLUCTUATION_CHECKINTERVAL;
		
		//reset known event sources
		knownEventSourcesList_.clear();
		
		// reset position
		curX_ = startingWayPoint_.getX();
		curY_ = startingWayPoint_.getY();
		curPosition_ = startingWayPoint_.getPositionOnStreet();
		curStreet_ = startingWayPoint_.getStreet();
		curWaitTime_ = startingWayPoint_.getWaittime();

		// recalculate routing information
		destinations_ = originalDestinations_.clone();
		if(curStreet_.isOneway()){
			while(!destinations_.isEmpty() && (!calculateRoute(false, false) || destinations_.peekFirst().getStreet() == curStreet_)){
				curWaitTime_ = destinations_.pollFirst().getWaittime();
			}
		} else {
			while(!destinations_.isEmpty() && (!calculateRoute(false, false) || destinations_.peekFirst().getStreet() == curStreet_)){
				curWaitTime_ = destinations_.pollFirst().getWaittime();
			}
		}
		if(curWaitTime_ == 0){
			active_ = true;
			curStreet_.addLaneObject(this, curDirection_);
		}
		calculatePosition();
		
		//reset region
		curRegion_.delVehicle(this);
		curRegion_ = MAP.getRegionOfPoint(curX_, curY_);
		curRegion_.addVehicle(this, false);
		
		mayBeRecycled_ = false;
	}
	
	/**
	 * Resets the global random number generator
	 */
	public static void resetGlobalRandomGenerator(){
		RANDOM.setSeed(1L);
	}
	

	/**
	 * Gets a substring of the Vehicle ID. Used in the EditOneVehicleControl.java chooseVehicle_ JCombobox.
	 */
	public String toString(){
		return Long.toHexString(ID_).substring(0,5);		
	}

	
	/**
	 * Indicates if this vehicle may be reset and reused.
	 * 
	 * @return	<code>true</code> if it may be reused, else <code>false</code>
	 */
	public boolean getMayBeRecycled(){
		return mayBeRecycled_;
	}

	/**
	 * Gets an array with all streets which will be visited until arriving at the next destination.
	 * 
	 * @return the array with all streets
	 */
	public Street[] getRouteStreets(){
		return routeStreets_;
	}

	/**
	 * Get the directions corresponding to the array returned <code>getRouteStreets()</code>.
	 * 
	 * @return the array with all directions
	 */
	public boolean[] getRouteDirections(){
		return routeDirections_;
	}

	/**
	 * Gets the current position in the array returned by <code>getRouteStreets()</code> and <code>getRouteDirections()</code>.
	 * 
	 * @return the position
	 */
	public int getRoutePosition(){
		return routePosition_;
	}


	/**
	 * Gets the current ID of this vehicle. This ID might change if mixing is enabled!
	 * 
	 * @return the ID
	 */
	public int getVehicleID(){
		return 0;
	}

	/**
	 * Gets the current communication countdown
	 * 
	 * @return the communication countdown
	 */
	public int getCommunicationCountdown(){
		return communicationCountdown_;
	}

	/**
	 * Gets the current beacon countdown
	 * 
	 * @return the beacon countdown
	 */
	public int getBeaconCountdown(){
		return beaconCountdown_;
	}

	/**
	 * Gets the starting point of the vehicle.
	 * 
	 * @return the <code>WayPoint</code>
	 */
	public WayPoint getStartPoint() {
		return startingWayPoint_;
	}

	/**
	 * Gets the regions x-coordinate in which this vehicle is found.
	 * 
	 * @return An Integer representing the x-coordinate of the Region
	 */
	public int getRegionX() {
		return curRegion_.getX();
	}

	/**
	 * Gets the regions y-coordinate in which this vehicle is found.
	 * 
	 * @return An Integer representing the y-coordinate of the Region
	 */
	public int getRegionY() {
		return curRegion_.getY();
	}

	/**
	 * Gets the maximum speed of this vehicle.
	 * 
	 * @return the maximum speed in cm/s
	 */
	public int getMaxSpeed(){
		return maxSpeed_;
	}

	/**
	 * Gets the current waittime.
	 * 
	 * @return the current waittime in milliseconds
	 */
	public int getWaittime(){
		if(curWaitTime_ < 0) return 0; 
		else return curWaitTime_;
	}

	/**
	 * Gets the destinations of this vehicle.
	 * 
	 * @return the <code>ArrayDeque</code> with all destinations
	 */
	public ArrayDeque<WayPoint> getDestinations(){
		return destinations_;
	}

	/**
	 * Gets the maximum communication distance of this vehicle.
	 * 
	 * @return the distance in cm
	 */
	public int getMaxCommDistance(){
		return maxCommDistance_;
	}

	/**
	 * Returns if this vehicle is currently active.
	 * 
	 * @return <code>true</code> if it's active
	 */
	public boolean isActive(){
		return active_;
	}

	/**
	 * Returns if this vehicle is currently in a mix zone.
	 * 
	 * @return <code>true</code> if it's in a mix zone
	 */
	public boolean isInMixZone(){
		return isInMixZone_;
	}

	/**
	 * Returns if this vehicle has WiFi functionality.
	 * 
	 * @return <code>true</code> if it has WiFi
	 */
	public boolean isWiFiEnabled(){
		return wiFiEnabled_;
	}

	/**
	 * Gets the special data structure with all known messages.
	 * 
	 * @return the data structure
	 */
	public KnownMessages getKnownMessages(){
		return knownMessages_;
	}
	
	/**
	 * Gets the special data structure with all known penalties.
	 * 
	 * @return the data structure
	 */
	public KnownPenalties getKnownPenalties(){
		return knownPenalties_;
	}

	/**
	 * Gets the special data structure with all known vehicles.
	 * 
	 * @return the data structure
	 */
	public KnownVehiclesList getKnownVehiclesList(){
		return knownVehiclesList_;
	}
	
	/**
	 * Gets the special data structure with all known RSUs.
	 * 
	 * @return the data structure
	 */
	public KnownRSUsList getKnownRSUsList(){
		return knownRSUsList_;
	}
	

	/**
	 * Returns how often this vehicle has changed it's ID (excluding the initial ID).
	 * 
	 * @return the amount
	 */
	public int getIDsChanged(){
		return IDsChanged_;
	}

	/**
	 * Gets how long this vehicle traveled. This excludes predefined waiting times but includes
	 * all other stops.
	 * 
	 * @return the total time in milliseconds
	 */
	public int getTotalTravelTime(){
		return totalTravelTime_;
	}

	/**
	 * The total distance traveled. This is not completely exact but should suffice in most cases.
	 * Small aberration from the real value occur if this vehicle reaches a destination (which should 
	 * not happen too often). 
	 * 
	 * @return the total distance in cm
	 */
	public long getTotalTravelDistance(){
		return totalTravelDistance_;
	}

	/**
	 * Sets the region in which this vehicle is found.
	 * 
	 * @param region	the region
	 */
	public void setRegion(Region region) {
		curRegion_ = region;
	}

	/**
	 * Gets the ID used in beacons encoded in HEX so that it's shorter. If the vehicle is not wifi
	 * enabled, brackets are used to indicate this.
	 * 
	 * @return the ID as an hex string
	 */
	public String getHexID(){
		if(wiFiEnabled_) return Long.toHexString(ID_);
		else return "(" + Long.toHexString(ID_) + ")"; //$NON-NLS-1$ //$NON-NLS-2$
	}
	
	/**
	 * Returns the interval between messages.
	 * 
	 * @return the interval in milliseconds
	 */
	public static int getCommunicationInterval(){
		return communicationInterval_;
	}

	/**
	 * Returns the interval between beacons.
	 * 
	 * @return the interval in milliseconds
	 */
	public static int getBeaconInterval(){
		return beaconInterval_;
	}


	/**
	 * Signals if communication is enabled.
	 * 
	 * @return	<code>true</code> if communication is enabled, else <code>false</code>
	 */
	public static boolean getCommunicationEnabled(){
		return communicationEnabled_;
	}
	
	/**
	 * Signals if recycling of vehicles is enabled or not
	 * 
	 * @return	<code>true</code> if recycling is enabled, else <code>false</code>
	 */
	public static boolean getRecyclingEnabled(){
		return recyclingEnabled_;
	}

	/**
	 * Signals if beacons are enabled.
	 * 
	 * @return <code>true</code> if beacons are enabled, else <code>false</code>
	 */
	public static boolean getBeaconsEnabled(){
		return beaconsEnabled_;
	}
	
	/**
	 * Signals if mix zones are enabled.
	 * 
	 * @return <code>true</code> if mix zones are enabled, else <code>false</code>
	 */
	public static boolean getMixZonesEnabled(){
		return mixZonesEnabled_;
	}
	
	/**
	 * If the fallback mode shall be enabled in mix zones. This fallback mode enables the beaconless
	 * communication inside mix zones.
	 * 
	 * @return <code>true</code> if the fallback mode is enabled, else <code>false</code>
	 */
	public static boolean getMixZonesFallbackEnabled(){
		return mixZonesFallbackEnabled_;
	}
	
	/**
	 * If the fallback mode only sends messages which are in flooding/broadcast mode.
	 * 
	 * @return <code>true</code> if only flooding messages are sent, else <code>false</code>
	 */
	public static boolean getMixZonesFallbackFloodingOnly(){
		return mixZonesFallbackFloodingOnly_;
	}

	/**
	 * Returns the current routing mode.
	 * 
	 * @return the routing mode
	 */
	public static int getRoutingMode(){
		return routingMode_;
	}

	/**
	 * Returns the maximum communication distance.
	 * 
	 * @return the maximum communication distance in cm
	 */
	public static int getMaximumCommunicationDistance(){
		return maximumCommunicationDistance_;
	}
	
	/**
	 * Gets the minimum time a vehicle needs to have traveled in order to be able to be recycled. Vehicles
	 * which travel shorter than this time will NOT get recycled. 
	 * 
	 * @return the time in milliseconds
	 */
	public static int getMinTravelTimeForRecycling(){
		return minTravelTimeForRecycling_;
	}

	/**
	 * Returns the radius of the mix zones.
	 * 
	 * @return the mix zone radius in cm
	 */
	public static int getMixZoneRadius(){
		return mixZoneRadius_;
	}

	/**
	 * Set the maximum radius of the mix zones.
	 * 
	 * @param maxMixZoneRadius	the maximum radius of the mix zones in cm
	 */
	public static void setMaxMixZoneRadius(int maxMixZoneRadius) {
		maxMixZoneRadius_ = maxMixZoneRadius;
	}

	/**
	 * Gets the maximum mix zone radius used in the scenario.
	 * 
	 * @return maxMixZoneRadius_ the maximum mix zone radius in cm
	 */
	public static int getMaxMixZoneRadius() {
		return maxMixZoneRadius_;
	}


	/**
	 * Set the default radius of the mix zones (in the common settings panel).
	 * 
	 * @param mixZoneRadius	the radius of the mix zones in cm
	 */
	public static void setMixZoneRadius(int mixZoneRadius){
		mixZoneRadius_ = mixZoneRadius;
	}
	
	/**
	 * Sets the minimum time a vehicle needs to have traveled in order to be able to be recycled. Vehicles
	 * which travel shorter than this time will NOT get recycled. 
	 * 
	 * @param minTravelTimeForRecycling	the time in milliseconds
	 */
	public static void setMinTravelTimeForRecycling(int minTravelTimeForRecycling){
		minTravelTimeForRecycling_ = minTravelTimeForRecycling;
	}

	/**
	 * Set the maximum communication distance.
	 * 
	 * @param maximumCommunicationDistance	the maximum communication distance in cm
	 */
	public static void setMaximumCommunicationDistance(int maximumCommunicationDistance){
		maximumCommunicationDistance_ = maximumCommunicationDistance;
	}

	/**
	 * Sets the reference to all regions. Call this on map reload!
	 * 
	 * @param regions	the array with all regions
	 */
	public static void setRegions(Region[][] regions){
		regions_ = regions;
	}

	/**
	 * Sets a new value for the communication interval. Common to all vehicles.
	 * 
	 * @param communicationInterval	the new value 
	 */
	public static void setCommunicationInterval(int communicationInterval){
		communicationInterval_ = communicationInterval;
	}

	/**
	 * Sets a new value for the beacon interval. Common to all vehicles.
	 * 
	 * @param beaconInterval	the new value 
	 */
	public static void setBeaconInterval(int beaconInterval){
		beaconInterval_ = beaconInterval;
	}

	/**
	 * Sets if communication is enabled or not. Common to all vehicles.
	 * 
	 * @param state	<code>true</code> to enable communication, else <code>false</code> 
	 */
	public static void setCommunicationEnabled(boolean state){
		RSU.setCommunicationEnabled(state);
		communicationEnabled_ = state;
	}
	
	/**
	 * Sets if recycling of vehicles is enabled or not. Common to all vehicles.
	 * 
	 * @param state	<code>true</code> to enable recycling, else <code>false</code> 
	 */
	public static void setRecyclingEnabled(boolean state){
		recyclingEnabled_ = state;
	}

	/**
	 * Sets if beacons are enabled or not. Common to all vehicles.
	 * 
	 * @param state	<code>true</code> to enable beacons, else <code>false</code> 
	 */
	public static void setBeaconsEnabled(boolean state){
		RSU.setBeaconsEnabled(state);
		beaconsEnabled_ = state;
	}

	/**
	 * Sets if mix zones are enabled or not. Common to all vehicles.
	 * 
	 * @param state	<code>true</code> to enable mix zones, else <code>false</code> 
	 */
	public static void setMixZonesEnabled(boolean state){
		mixZonesEnabled_ = state;
	}
	
	/**
	 * Sets if the fallback mode shall be enabled in mix zones. This fallback mode enables the beaconless
	 * communication inside mix zones.
	 * 
	 * @param state	<code>true</code> if the fallback mode is enabled, else <code>false</code>
	 */
	public static void setMixZonesFallbackEnabled(boolean state){
		mixZonesFallbackEnabled_ = state;
	}
	
	/**
	 * Sets if the fallback mode only sends messages which are in flooding/broadcast mode.
	 * 
	 * @param state	<code>true</code> if only flooding messages are sent, else <code>false</code>
	 */
	public static void setMixZonesFallbackFloodingOnly(boolean state){
		mixZonesFallbackFloodingOnly_ = state;
	}
	
	/**
	 * Sets if beacon zones should be monitored or not. Common to all vehicles.
	 * 
	 * @param beaconMonitorEnabled	<code>true</code> to enable monitoring mix zones, else <code>false</code> 
	 */
	public static void setBeaconMonitorZoneEnabled(boolean beaconMonitorEnabled){
		beaconMonitorEnabled_ = beaconMonitorEnabled;
		RSU.setBeaconMonitorZoneEnabled(beaconMonitorEnabled);
	}
	
	/**
	 * Gets beacon monitor status
	 * 
	 * @return beaconMonitorEnabled_ <code>true</code> if beacon monitor is enabled
	 */
	public static boolean getbeaconMonitorEnabled() {
		return beaconMonitorEnabled_;
	}
	
	/**
	 * Sets the values for the monitored beacon zone. A rectangular bounding box within the specified coordinates
	 * is monitored if {@link #setBeaconMonitorZoneEnabled(boolean)} is set to <code>true</code>.
	 * 
	 * @param beaconMonitorMinX	the minimum x coordinate
	 * @param beaconMonitorMaxX	the maximum x coordinate
	 * @param beaconMonitorMinY	the minimum y coordinate
	 * @param beaconMonitorMaxY	the maximum y coordinate
	 */
	public static void setMonitoredMixZoneVariables(int beaconMonitorMinX, int beaconMonitorMaxX, int beaconMonitorMinY, int beaconMonitorMaxY){
		beaconMonitorMinX_ = beaconMonitorMinX;
		beaconMonitorMaxX_ = beaconMonitorMaxX;
		beaconMonitorMinY_ = beaconMonitorMinY;
		beaconMonitorMaxY_ = beaconMonitorMaxY;		
		RSU.setMonitoredMixZoneVariables(beaconMonitorMinX,beaconMonitorMaxX,beaconMonitorMinY,beaconMonitorMaxY);
	}
	
	/**
	 * Gets beacon monitor minX coordinate
	 * 
	 * @return beaconMonitorMinX_ the minX coordinate of the beacon monitor window
	 */
	public static int getbeaconMonitorMinX() {
		return beaconMonitorMinX_;
	}
	
	/**
	 * Gets beacon monitor maxX coordinate
	 * 
	 * @return beaconMonitorMaxX_ the maxX coordinate of the beacon monitor window
	 */
	public static int getbeaconMonitorMaxX() {
		return beaconMonitorMaxX_;
	}
	
	/**
	 * Gets beacon monitor minY coordinate
	 * 
	 * @return beaconMonitorMinY_ the minY coordinate of the beacon monitor window
	 */
	public static int getbeaconMonitorMinY() {
		return beaconMonitorMinX_;
	}
	
	/**
	 * Gets beacon monitor maxY coordinate
	 * 
	 * @return beaconMonitorMaxY_ the maxY coordinate of the beacon monitor window
	 */
	public static int getbeaconMonitorMaxY() {
		return beaconMonitorMaxY_;
	}

	/**
	 * Gets the report panel for beacon monitoring
	 * 
	 * @return REPORT_PANEL the beacon report panel
	 */
	public static ReportingControlPanel getREPORT_PANEL() {
		return REPORT_PANEL;
	}
	/**
	 * Sets a new routing mode. See the A_Star_Algor for details. Common to all vehicles.
	 * 
	 * @param mode	the new routing mode
	 */
	public static void setRoutingMode(int mode){
		routingMode_ = mode;
	}

	/**
	 * Gets the vehicle ID
	 * 
	 * @return ID_ the vehicle ID
	 */
	public long getID() {
		return ID_;
	}

	/**
	 * Set vehicle WiFi
	 * 
	 * @param wiFiEnabled <code>true</code> to enable WiFi for the vehicle
	 */
	public void setWiFiEnabled(boolean wiFiEnabled) {
		wiFiEnabled_ = wiFiEnabled;
	}


	/**
	 * Sets the maximum speed
	 * 
	 * @param maxSpeed the speed in cm/s
	 */
	public void setMaxSpeed(int maxSpeed) {
		maxSpeed_ = maxSpeed;
	}

	/**
	 * Sets the maximum communication distance
	 * 
	 * @param maxCommDistance the maximum communication distance in cm
	 */
	public void setMaxCommDistance(int maxCommDistance) {
		maxCommDistance_ = maxCommDistance;
	}

	/**
	 * Sets the current wait time.
	 * 
	 * @param curWaitTime the current wait time in ms.
	 */
	public void setCurWaitTime(int curWaitTime) {
		curWaitTime_ = curWaitTime;
	}

	/**
	 * Gets the current wait time
	 * 
	 * @return curWaitTime_ the current wait time
	 */
	public int getCurWaitTime() {
		return curWaitTime_;
	}

	/**
	 * Sets the color
	 * 
	 * @param color the new color
	 */
	public void setColor(Color color) {
		color_ = color;
	}

	/**
	 * Gets the vehicle color.
	 * 
	 * @return color_ the vehicle color.
	 */
	public Color getColor() {
		return color_;
	}

	/**
	 * Sets the braking rate
	 * 
	 * @param brakingRate the braking rate in cm/s^2
	 */
	public void setBrakingRate(int brakingRate) {
		if(brakingRate <= 0) brakingRate_ = 300;
		else brakingRate_ = brakingRate;	
	}

	/**
	 * Gets the braking rate
	 * 
	 * @return brakingRate_ the braking rate in cm/s^2
	 */
	public int getBrakingRate() {
		return brakingRate_;
	}

	/**
	 * Sets the acceleration rate
	 * 
	 * @param accelerationRate the acceleration rate in cm/s^2
	 */
	public void setAccelerationRate(int accelerationRate) {
		if(accelerationRate <= 0) accelerationRate_ = 800;
		else accelerationRate_ = accelerationRate;	
	}

	/**
	 * Gets the acceleration rate
	 * 
	 * @return accelerationRate_ the acceleration rate in cm/s^2
	 */
	public int getAccelerationRate() {
		return accelerationRate_;
	}

	/**
	 * Sets the emergency vehicle mode
	 * 
	 * @param emergencyVehicle <code>true</code> to enable emergency mode
	 */
	public void setEmergencyVehicle(boolean emergencyVehicle) {
		emergencyVehicle_ = emergencyVehicle;
	}

	/**
	 * Signals if vehicle is an emergency vehicle
	 * 
	 * @return <code>true</code> if vehicle is an emergency vehicle
	 */
	public boolean isEmergencyVehicle() {
		return emergencyVehicle_;
	}

	/**
	 * Sets the vehicle length
	 * 
	 * @param vehicleLength the vehicle length in cm.
	 */ 
	public void setVehicleLength(int vehicleLength) {
		vehicleLength_ = vehicleLength;
	}

	/**
	 * Gets the vehicle length.
	 * 
	 * @return vehicleLength_ the vehicle length in cm.
	 */
	public int getVehicleLength() {
		return vehicleLength_;
	}


	public static AttackRSU[] getArsuList() {
		return arsuList;
	}


	public static void setArsuList(AttackRSU[] arsuList) {
		Vehicle.arsuList = arsuList;
	}


	public static boolean isAttackerDataLogged_() {
		return attackerDataLogged_;
	}


	public static void setAttackerDataLogged_(boolean attackerDataLogged_) {
		Vehicle.attackerDataLogged_ = attackerDataLogged_;
	}


	public static long getAttackedVehicleID_() {
		return attackedVehicleID_;
	}


	public static void setAttackedVehicleID_(long attackedVehicleID_) {
		Vehicle.attackedVehicleID_ = attackedVehicleID_;
	}


	public static boolean isEncryptedBeaconsInMix_() {
		return encryptedBeaconsInMix_;
	}


	public static void setEncryptedBeaconsInMix_(boolean encryptedBeaconsInMix_) {
		Vehicle.encryptedBeaconsInMix_ = encryptedBeaconsInMix_;
	}


	public static boolean isAttackerEncryptedDataLogged_() {
		return attackerEncryptedDataLogged_;
	}


	public static void setAttackerEncryptedDataLogged_(
			boolean attackerEncryptedDataLogged_) {
		Vehicle.attackerEncryptedDataLogged_ = attackerEncryptedDataLogged_;
	}


	public Node getCurMixNode_() {
		return curMixNode_;
	}


	public void setCurMixNode_(Node curMixNode_) {
		this.curMixNode_ = curMixNode_;
	}

	public static ReportingControlPanel getReportingPanel(){
		if(Renderer.getInstance().isConsoleStart()) return null;
		else return VanetSimStart.getMainControlPanel().getReportingPanel();
	}


	/**
	 * @return the waitingForSignal_
	 */
	public boolean isWaitingForSignal_() {
		return waitingForSignal_;
	}


	/**
	 * @param waitingForSignal_ the waitingForSignal_ to set
	 */
	public void setWaitingForSignal_(boolean waitingForSignal_) {
		this.waitingForSignal_ = waitingForSignal_;
	}


	public static boolean isPrivacyDataLogged_() {
		return privacyDataLogged_;
	}


	public static void setPrivacyDataLogged_(boolean privacyDataLogged_) {
		Vehicle.privacyDataLogged_ = privacyDataLogged_;
	}

	public void setTimeDistance(int timeDistance) {
		timeDistance_ = timeDistance;
	}


	public int getTimeDistance() {
		return timeDistance_;
	}

	public void setPoliteness(int politeness_) {
		this.politeness_ = politeness_;
	}


	public int getPoliteness() {
		return politeness_;
	}

	public static int getTIME_BETWEEN_SILENT_PERIODS() {
		return TIME_BETWEEN_SILENT_PERIODS;
	}

	public static void setTIME_BETWEEN_SILENT_PERIODS(int i){
		TIME_BETWEEN_SILENT_PERIODS = i;
	}

	public static int getTIME_OF_SILENT_PERIODS() {
		return TIME_OF_SILENT_PERIODS;
	}

	public static void setTIME_OF_SILENT_PERIODS(int i){
		TIME_OF_SILENT_PERIODS = i;
	}

	public static boolean isSilent_period() {
		return silent_period;
	}


	public static void setSilent_period(boolean silent_period) {
		Vehicle.silent_period = silent_period;
	}


	public static boolean isSilentPeriodsOn() {
		return silentPeriodsOn;
	}


	public static void setSilentPeriodsOn(boolean silentPeriodsOn) {
		Vehicle.silentPeriodsOn = silentPeriodsOn;
	}


	/**
	 * @return the tIME_TO_PSEUDONYM_CHANGE
	 */
	public static int getTIME_TO_PSEUDONYM_CHANGE() {
		return TIME_TO_PSEUDONYM_CHANGE;
	}


	/**
	 * @param tIME_TO_PSEUDONYM_CHANGE the tIME_TO_PSEUDONYM_CHANGE to set
	 */
	public static void setTIME_TO_PSEUDONYM_CHANGE(int tIME_TO_PSEUDONYM_CHANGE) {
		TIME_TO_PSEUDONYM_CHANGE = tIME_TO_PSEUDONYM_CHANGE;
	}


	/**
	 * @return the sLOW_SPEED_LIMIT
	 */
	public static int getSLOW_SPEED_LIMIT() {
		return SLOW_SPEED_LIMIT;
	}


	/**
	 * @param sLOW_SPEED_LIMIT the sLOW_SPEED_LIMIT to set
	 */
	public static void setSLOW_SPEED_LIMIT(int sLOW_SPEED_LIMIT) {
		SLOW_SPEED_LIMIT = sLOW_SPEED_LIMIT;
	}


	/**
	 * @return the slowOn
	 */
	public static boolean isSlowOn() {
		return slowOn;
	}


	/**
	 * @param slowOn the slowOn to set
	 */
	public static void setSlowOn(boolean slowOn) {
		Vehicle.slowOn = slowOn;
	}


	/**
	 * @return the isInSlow
	 */
	public boolean isInSlow() {
		return isInSlow;
	}


	/**
	 * @param isInSlow the isInSlow to set
	 */
	public void setInSlow(boolean isInSlow) {
		this.isInSlow = isInSlow;
	}


	/**
	 * @return the changedPseudonymInSlow
	 */
	public boolean isChangedPseudonymInSlow() {
		return changedPseudonymInSlow;
	}


	/**
	 * @param changedPseudonymInSlow the changedPseudonymInSlow to set
	 */
	public void setChangedPseudonymInSlow(boolean changedPseudonymInSlow) {
		this.changedPseudonymInSlow = changedPseudonymInSlow;
	}


	/**
	 * @return the slowTimestamp
	 */
	public int getSlowTimestamp() {
		return slowTimestamp;
	}


	/**
	 * @param slowTimestamp the slowTimestamp to set
	 */
	public void setSlowTimestamp(int slowTimestamp) {
		this.slowTimestamp = slowTimestamp;
	}


	/**
	 * @return the speedDeviation_
	 */
	public int getSpeedDeviation_() {
		return speedDeviation_;
	}


	/**
	 * @param speedDeviation_ the speedDeviation_ to set
	 */
	public void setSpeedDeviation_(int speedDeviation_) {
		this.speedDeviation_ = speedDeviation_;
	}


	/**
	 * @return the idsActivated
	 */
	public static boolean isIdsActivated() {
		return idsActivated;
	}


	/**
	 * @param idsActivated the idsActivated to set
	 */
	public static void setIdsActivated(boolean idsActivated) {
		Vehicle.idsActivated = idsActivated;
	}


	/**
	 * @return the moveOutOfTheWay
	 */
	public boolean isMoveOutOfTheWay_() {
		return moveOutOfTheWay_;
	}


	/**
	 * @param moveOutOfTheWay the moveOutOfTheWay to set
	 */
	public void setMoveOutOfTheWay_(boolean moveOutOfTheWay) {
		moveOutOfTheWay_ = moveOutOfTheWay;
	}


	/**
	 * @return the fakingMessages_
	 */
	public boolean isFakingMessages() {
		return fakingMessages_;
	}


	/**
	 * @param fakingMessages_ the fakingMessages_ to set
	 */
	public void setFakingMessages(boolean fakingMessages) {
		fakingMessages_ = fakingMessages;
	}


	/**
	 * @return the fakeMessageType
	 */
	public String getFakeMessageType() {
		return fakeMessageType_;
	}


	/**
	 * @param fakeMessageType the fakeMessageType to set
	 */
	public void setFakeMessageType(String fakeMessageType) {
		fakeMessageType_ = fakeMessageType;
	}


	/**
	 * @return the fakeMessagesInterval_
	 */
	public static int getFakeMessagesInterval_() {
		return fakeMessagesInterval_;
	}


	/**
	 * @param fakeMessagesInterval_ the fakeMessagesInterval_ to set
	 */
	public static void setFakeMessagesInterval_(int fakeMessagesInterval_) {
		Vehicle.fakeMessagesInterval_ = fakeMessagesInterval_;
	}



	/**
	 * @return the emergencyBrakingCountdown_
	 */
	public long getEmergencyBrakingCountdown_() {
		return emergencyBrakingCountdown_;
	}


	/**
	 * @param emergencyBrakingCountdown_ the emergencyBrakingCountdown_ to set
	 */
	public void setEmergencyBrakingCountdown_(int emergencyBrakingCountdown_) {
		this.emergencyBrakingCountdown_ = emergencyBrakingCountdown_;
	}


	/**
	 * @return the emergencyBrakingDuration_
	 */
	public int getEmergencyBrakingDuration_() {
		return emergencyBrakingDuration_;
	}


	/**
	 * @param emergencyBrakingDuration_ the emergencyBrakingDuration_ to set
	 */
	public void setEmergencyBrakingDuration_(int emergencyBrakingDuration_) {
		this.emergencyBrakingDuration_ = emergencyBrakingDuration_;
	}


	/**
	 * @return the stopTime_
	 */
	public int getStopTime_() {
		return stopTime_;
	}


	/**
	 * @param forwardMessage_ the forwardMessage_ to set
	 */
	public void setForwardMessage_(boolean forwardMessage_) {
		this.forwardMessage_ = forwardMessage_;
	}


	/**
	 * @return the random
	 */
	public static Random getRandom() {
		return RANDOM;
	}


	/**
	 * @return the doNotRecycle_
	 */
	public boolean isDoNotRecycle_() {
		return doNotRecycle_;
	}


	/**
	 * @param doNotRecycle_ the doNotRecycle_ to set
	 */
	public void setDoNotRecycle_(boolean doNotRecycle_) {
		this.doNotRecycle_ = doNotRecycle_;
	}


	/**
	 * @return the emergencyBeacons
	 */
	public int getEmergencyBeacons() {
		return emergencyBeacons;
	}


	/**
	 * @param emergencyBeacons the emergencyBeacons to set
	 */
	public void setEmergencyBeacons(int emergencyBeacons) {
		this.emergencyBeacons = emergencyBeacons;
	}


	/**
	 * @return the waitingForVehicle_
	 */
	public Vehicle getWaitingForVehicle_() {
		return waitingForVehicle_;
	}


	/**
	 * @param waitingForVehicle_ the waitingForVehicle_ to set
	 */
	public void setWaitingForVehicle_(Vehicle waitingForVehicle_) {
		this.waitingForVehicle_ = waitingForVehicle_;
	}


	/**
	 * @return the drivingOnTheSide_
	 */
	public boolean isDrivingOnTheSide_() {
		return drivingOnTheSide_;
	}


	/**
	 * @return the idsProcessorList_
	 */
	public IDSProcessorList getIdsProcessorList_() {
		return idsProcessorList_;
	}


	/**
	 * @return the passingBlocking_
	 */
	public boolean isPassingBlocking_() {
		return passingBlocking_;
	}


	/**
	 * @param passingBlocking_ the passingBlocking_ to set
	 */
	public void setPassingBlocking_(boolean passingBlocking_) {
		this.passingBlocking_ = passingBlocking_;
	}


	/**
	 * @return the pcnMessagesCreated_
	 */
	public int getPcnMessagesCreated_() {
		return pcnMessagesCreated_;
	}


	/**
	 * @return the pcnForwardMessagesCreated_
	 */
	public int getPcnForwardMessagesCreated_() {
		return pcnForwardMessagesCreated_;
	}


	/**
	 * @return the evaMessagesCreated_
	 */
	public int getEvaMessagesCreated_() {
		return evaMessagesCreated_;
	}


	/**
	 * @return the evaForwardMessagesCreated_
	 */
	public int getEvaForwardMessagesCreated_() {
		return evaForwardMessagesCreated_;
	}


	/**
	 * @return the rhcnMessagesCreated_
	 */
	public int getRhcnMessagesCreated_() {
		return rhcnMessagesCreated_;
	}


	/**
	 * @return the eeblMessagesCreated_
	 */
	public int getEeblMessagesCreated_() {
		return eeblMessagesCreated_;
	}


	/**
	 * @return the fakeMessagesCreated_
	 */
	public int getFakeMessagesCreated_() {
		return fakeMessagesCreated_;
	}


	public boolean isInTrafficJam_() {
		return inTrafficJam_;
	}


	public void setInTrafficJam_(boolean inTrafficJam_) {
		this.inTrafficJam_ = inTrafficJam_;
	}


	/**
	 * @return the checkIDSProcessors_
	 */
	public boolean isCheckIDSProcessors_() {
		return checkIDSProcessors_;
	}


	/**
	 * @param checkIDSProcessors_ the checkIDSProcessors_ to set
	 */
	public void setCheckIDSProcessors_(boolean checkIDSProcessors_) {
		this.checkIDSProcessors_ = checkIDSProcessors_;
	}


	public void setEmergencyBraking_(boolean emergencyBraking_) {
		this.emergencyBraking_ = emergencyBraking_;
	}


	public boolean isEmergencyBraking_() {
		return emergencyBraking_;
	}


	public boolean isEEBLmessageIsCreated_() {
		return EEBLmessageIsCreated_;
	}


	public void setEEBLmessageIsCreated_(boolean eEBLmessageIsCreated_) {
		EEBLmessageIsCreated_ = eEBLmessageIsCreated_;
	}


	public KnownEventSourcesList getKnownEventSourcesList_() {
		return knownEventSourcesList_;
	}


	public int getSpamCounter_() {
		return spamCounter_;
	}


	public void setSpamCounter_(int spamCounter_) {
		this.spamCounter_ = spamCounter_;
	}


	public int getMessagesCounter_() {
		return messagesCounter_;
	}


	public void setMessagesCounter_(int messagesCounter_) {
		this.messagesCounter_ = messagesCounter_;
	}


	public Random getOwnRandom_() {
		return ownRandom_;
	}


	public int getEVAMessageDelay_() {
		return EVAMessageDelay_;
	}

	public void setEVAMessageDelay_(int eVAMessageDelay_) {
		EVAMessageDelay_ = eVAMessageDelay_;
	}
	
	public static int getMaxEVAMessageDelay_() {
		return maxEVAMessageDelay_;
	}

	public static void setMaxEVAMessageDelay_(int theMaxEVAMessageDelay_) {
		maxEVAMessageDelay_ = theMaxEVAMessageDelay_;
	}


	public boolean isLogBeaconsAfterEvent_() {
		return logBeaconsAfterEvent_;
	}


	public void setLogBeaconsAfterEvent_(boolean logBeaconsAfterEvent_) {
		this.logBeaconsAfterEvent_ = logBeaconsAfterEvent_;
	}


	public int getAmountOfLoggedBeacons_() {
		return amountOfLoggedBeacons_;
	}


	public void setAmountOfLoggedBeacons_(int amountOfLoggedBeacons_) {
		this.amountOfLoggedBeacons_ = amountOfLoggedBeacons_;
	}


	public String getBeaconString_() {
		return beaconString_;
	}


	public void setBeaconString_(String beaconString_) {
		this.beaconString_ = beaconString_;
	}

}