/*
 * Title:        CloudSim Toolkit
 * Description:  CloudSim (Cloud Simulation) Toolkit for Modeling and Simulation of Clouds
 * Licence:      GPL - http://www.gnu.org/copyleft/gpl.html
 *
 * Copyright (c) 2009-2010, The University of Melbourne, Australia
 */

package org.cloudbus.cloudsim.core;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.cloudbus.cloudsim.Log;
import org.cloudbus.cloudsim.core.predicates.Predicate;
import org.cloudbus.cloudsim.core.predicates.PredicateAny;
import org.cloudbus.cloudsim.core.predicates.PredicateNone;

/**
 * 这个类主要作用是把几个核心类组成系统(CIS,QUEUE,CLOUDSIMSHUTDOWN)
 * 主要包括CIS
 * cloudsim中所有的字段和方法都是static
 * This class extends the CloudSimCore to enable network simulation in CloudSim.
 * Also, it disables all the network models from CloudSim, to provide a simpler
 * simulation of networking. In the network model used by CloudSim, a topology
 * file written in BRITE format is used to describe the network. Later, nodes in
 * such file are mapped to CloudSim entities. Delay calculated from the BRITE
 * model are added to the messages send through CloudSim. Messages using the old
 * model are converted to the apropriate methods with the correct parameters.
 *
 * @author		Rodrigo N. Calheiros
 * @author		Anton Beloglazov
 * @since		CloudSim Toolkit 1.0
 */
public class CloudSim {

	/** The Constant CLOUDSIM_VERSION_STRING. */
	private static final String CLOUDSIM_VERSION_STRING = "2.0";

	/** The id of CIS entity. */
	private static int cisId = -1;

	/** The id of CloudSimShutdown entity. */
	@SuppressWarnings("unused")
	private static int shutdownId = -1;

	/** The CIS object. */
	private static CloudInformationService cis = null;

	/** The Constant NOT_FOUND. */
	private static final int NOT_FOUND = -1;

	/** The trace flag. */
	@SuppressWarnings("unused")
	private static boolean traceFlag = false;

	/** The calendar. */
	private static Calendar calendar = null;

	/**
	 * 初始化实体列表,实体hash,future,defered,calendar,traceflag,cloudsimshutdown
	 * Initialises all the common attributes.
	 *
	 * @param _calendar the _calendar
	 * @param _traceFlag the _trace flag
	 * @param numUser number of users
	 * @throws Exception This happens when creating this entity before initialising
	 * CloudSim package or this entity name is <tt>null</tt> or empty
	 * @pre $none
	 * @post $none
	 */
	private static void initCommonVariable(Calendar _calendar, boolean _traceFlag, int numUser) throws Exception {
		//初始化实体列表,实体hash,future,defered,等
		initialize();
		// NOTE: the order for the below 3 lines are important
		traceFlag = _traceFlag;

		// Set the current Wall clock time as the starting time of
		// simulation
		if (_calendar == null) {
			calendar = Calendar.getInstance();
		} else {
			calendar = _calendar;
		}

		// creates a CloudSimShutdown object
		CloudSimShutdown shutdown = new CloudSimShutdown("CloudSimShutdown", numUser);
		shutdownId = shutdown.getId();           //id默认为-1
	}

	/**
	 * Initialises CloudSim parameters. This method should be called before
	 * creating any entities.
	 * <p>
	 * Inside this method, it will create the following CloudSim entities:
	 * <ul>
	 * <li>CloudInformationService.
	 * <li>CloudSimShutdown
	 * </ul>
	 * <p>
	 *
	 * @param numUser the number of User Entities created. This parameters indicates
	 * that {@link gridsim.CloudSimShutdown} first waits for all user
	 * entities's END_OF_SIMULATION signal before issuing terminate
	 * signal to other entities
	 * @param cal starting time for this simulation. If it is <tt>null</tt>,
	 * then the time will be taken from
	 * <tt>Calendar.getInstance()</tt>
	 * @param traceFlag <tt>true</tt> if CloudSim trace need to be written
	 *
	 * @see gridsim.CloudSimShutdown
	 * @see CloudInformationService.CloudInformationService
	 * @pre numUser >= 0
	 * @post $none
	 */
	public static void init(int numUser, Calendar cal, boolean traceFlag) {
		try {
			initCommonVariable(cal, traceFlag, numUser);

			// create a GIS object
			cis = new CloudInformationService("CloudInformationService");

			// set all the above entity IDs
			cisId = cis.getId();
		} catch (IllegalArgumentException s) {
			Log.printLine("CloudSim.init(): Unwanted errors happen");
			Log.printLine(s.getMessage());
		} catch (Exception e) {
			Log.printLine("CloudSim.init(): Unwanted errors happen");
			Log.printLine(e.getMessage());
		}
	}

	/**
	 * Starts the execution of CloudSim simulation. It waits for complete
	 * execution of all entities, i.e. until all entities threads reach
	 * non-RUNNABLE state or there are no more events in the future event queue.
	 * <p>
	 * <b>Note</b>: This method should be called after all the entities have
	 * been setup and added.
	 *
	 * @return the double
	 * @throws NullPointerException This happens when creating this entity before initialising
	 * CloudSim package or this entity name is <tt>null</tt> or
	 * empty.
	 * @see gridsim.CloudSim#init(int, Calendar, boolean)
	 * @pre $none
	 * @post $none
	 */
	public static double startSimulation() throws NullPointerException {
		Log.printLine("Starting CloudSim version " + CLOUDSIM_VERSION_STRING);
		try {
			double clock = run();

			// reset all static variables
			cisId = -1;
			shutdownId = -1;
			cis = null;
			calendar = null;
			traceFlag = false;

			return clock;
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
			throw new NullPointerException("CloudSim.startCloudSimulation() :"
					+ " Error - you haven't initialized CloudSim.");
		}
	}

	/**
	 *仿真停止。
	 * Stops Cloud Simulation (based on {@link Simulation#runStop()}). This
	 * should be only called if any of the user defined entities
	 * <b>explicitly</b> want to terminate simulation during execution.
	 *
	 * @throws NullPointerException This happens when creating this entity before initialising
	 * CloudSim package or this entity name is <tt>null</tt> or empty
	 *
	 * @see gridsim.CloudSim#init(int, Calendar, boolean)
	 * @see Simulation#runStop()
	 * @pre $none
	 * @post $none
	 */
	public static void stopSimulation() throws NullPointerException {
		try {
			runStop();
		} catch (IllegalArgumentException e) {
			throw new NullPointerException("CloudSim.stopCloudSimulation() : "
					+ "Error - can't stop Cloud Simulation.");
		}
	}

	/**
	 *  复制日历
	 * Gets a new copy of initial simulation Calendar.
	 *
	 * @return a new copy of Calendar object or  if CloudSim hasn't
	 * been initialized
	 * @see gridsim.CloudSim#init(int, Calendar, boolean, String[], String[],
	 * String)
	 * @see gridsim.CloudSim#init(int, Calendar, boolean)
	 * @pre $none
	 * @post $none
	 */
	public static Calendar getSimulationCalendar() {
		// make a new copy
		Calendar clone = calendar;
		if (calendar != null) {
			clone = (Calendar) calendar.clone();
		}

		return clone;
	}

	/**
	 * 获得CIS的id
	 * Gets the entity ID of <tt>CloudInformationService</tt>.
	 *
	 * @return the Entity ID or  if it is not found
	 * @pre $none
	 * @post $result >= -1
	 */
	public static int getCloudInfoServiceEntityId() {
		return cisId;
	}

	/**
	 * 所得CIS中所有实体列表
	 * Sends a request to Cloud Information Service (GIS) entity to get the list
	 * of all Cloud hostList.
	 *
	 * @return A List containing CloudResource ID (as an Integer object)
	 * or  if a CIS entity hasn't been created before
	 * @pre $none
	 * @post $none
	 */
	public static List<Integer> getCloudResourceList() {
		if (cis == null) {
			return null;
		}

		return cis.getList();
	}

	// ======== SIMULATION METHODS ===============//

	// Private data members
	/** The entities. */
	private static List<SimEntity> entities;

	/** The future event queue. */
	private static FutureQueue future;

	/** The deferred event queue. */
	private static DeferredQueue deferred;

	/** The simulation clock. */
	private static double clock;

	/** Flag for checking if the simulation is running. */
	private static boolean running;

	/*
	 * (non-javadoc)
	 */
	/** The entities by name. */
	private static Map<String, SimEntity> entitiesByName;

	// The predicates used in entity wait methods
	/** The wait predicates. */
	private static Map<Integer, Predicate> waitPredicates;

	/** The paused. */
	private static boolean paused = false;

	/** The pause at. */
	private static long pauseAt = -1;

	/** The abrupt terminate. */
	private static boolean abruptTerminate = false;

	/**
	 * 初始化实体列表,实体hash,future,defered,等
	 * Initialise the simulation for stand alone simulations. This function
	 * should be called at the start of the simulation.
	 */
	protected static void initialize() {
		Log.printLine("Initialising...");
		entities = new ArrayList<SimEntity>();
		entitiesByName = new LinkedHashMap<String, SimEntity>();
		future = new FutureQueue();
		deferred = new DeferredQueue();
		waitPredicates = new HashMap<Integer, Predicate>();
		clock = 0;
		running = false;
	}

	// The two standard predicates

	/** A standard predicate that matches any event. */
	public final static PredicateAny SIM_ANY = new PredicateAny();

	/** A standard predicate that does not match any events. */
	public final static PredicateNone SIM_NONE = new PredicateNone();

	// Public access methods

	/**
	 * 返回时钟
	 * Get the current simulation time.
	 *
	 * @return the simulation time
	 */
	public static double clock() {
		return clock;
	}

	/**
	 * 返回仿真实体数量
	 * Get the current number of entities in the simulation.
	 *
	 * @return The number of entities
	 */
	public static int getNumEntities() {
		return entities.size();
	}

	/**
	 * Get the entity with a given id.
	 * 
	 * @param id the entity's unique id number
	 * @return The entity, or  if it could not be found
	 */
	public static SimEntity getEntity(int id) {
		return entities.get(id);
	}

	/**
	 * Get the entity with a given name.
	 *
	 * @param name The entity's name
	 * @return The entity
	 */
	public static SimEntity getEntity(String name) {
		return entitiesByName.get(name);
	}

	/**
	 * Get the id of an entity with a given name.
	 *
	 * @param name The entity's name
	 * @return The entity's unique id number
	 */
	public static int getEntityId(String name) {
		SimEntity obj = entitiesByName.get(name);
		if (obj == null) {
			return NOT_FOUND;
		} else {
			return obj.getId();
		}
	}

	/**
	 * Gets name of the entity given its entity ID.
	 *
	 * @param entityID the entity ID
	 * @return the Entity name or  if this object does not have one
	 * @pre entityID > 0
	 * @post $none
	 */
	public static String getEntityName(int entityID) {
		try {
			return getEntity(entityID).getName();
		} catch (IllegalArgumentException e) {
			return null;
		} catch (Exception e) {
			return null;
		}
	}

	/**
	 * Gets name of the entity given its entity ID.
	 *
	 * @param entityID the entity ID
	 * @return the Entity name or  if this object does not have one
	 * @pre entityID > 0
	 * @post $none
	 */
	public static String getEntityName(Integer entityID) {
		if (entityID != null) {
			return getEntityName(entityID.intValue());
		}
		return null;
	}

	/**
	 * Returns a list of entities created for the simulation.
	 *
	 * @return the entity iterator
	 */
	public static List<SimEntity> getEntityList() {
		// create a new list to prevent the user from changing
		// the list of entities used by Simulation
		List<SimEntity> list = new LinkedList<SimEntity>();
		list.addAll(entities);
		return list;
	}

	// Public update methods

	/**
	 * 实体加入仿真中,创建一个crate的事件(其他还有空事件,发送事件,等待事件)加入到future中
	 * Add a new entity to the simulation. This is present for compatibility
	 * with existing simulations since entities are automatically added to the
	 * simulation upon instantiation.
	 *
	 * @param e The new entity
	 */
	public static void addEntity(SimEntity e) {
		SimEvent evt;
		//??为什么还要发送一个事件??
		if (running) {
			// Post an event to make this entity
			evt = new SimEvent(SimEvent.CREATE, clock, 1, 0, 0, e);
			future.addEvent(evt);
		}
		//实体加入到entities列表中了
		if (e.getId() == -1) { // Only add once!
			int id = entities.size();
			e.setId(id);
			entities.add(e);
			entitiesByName.put(e.getName(), e);
		}
	}

	/**
	 * 内部用来添加一个实体,当仿真在运行时候
	 * ??没有加入队列???
	 * Internal method used to add a new entity to the simulation when the
	 * simulation is running. It should <b>not</b> be called from user
	 * simulations.
	 *
	 * @param e The new entity
	 */
	protected static void addEntityDynamically(SimEntity e) {
		if (e == null) {
			throw new IllegalArgumentException("Adding null entity.");
		} else {
			printMessage("Adding: " + e.getName());
		}
		e.startEntity();
	}

	/**
	 * 仿真跑一个时刻,处理defered中所有剩下的事件,处理future中所有和第一个事件
	 * 发生时间相同的事件
	 * Internal method used to run one tick of the simulation. This method
	 * should <b>not</b> be called in simulations.
	 *
	 * @return true, if successful
	 * otherwise
	 */
	public static boolean runClockTick() {
		SimEntity ent;
		boolean queue_empty;
		int entities_size = entities.size();
		
		//处理所有defered中的事件
		for (int i = 0; i < entities_size; i++) {
			ent = entities.get(i);
			if (ent.getState() == SimEntity.RUNNABLE) {
				ent.run();
			}
		}

		// If there are more future events then deal with them
		//处理future中所有和第一个事件发生时间相同的事件
		if (future.size() > 0) {
			List<SimEvent> toRemove = new ArrayList<SimEvent>();
			Iterator<SimEvent> it = future.iterator();
			queue_empty = false;
			SimEvent first = it.next();
			processEvent(first);
			future.remove(first);

			it = future.iterator();

			// Check if next events are at same time...
			boolean trymore = it.hasNext();
			while (trymore) {
				SimEvent next = it.next();
				if (next.eventTime() == first.eventTime()) {
					processEvent(next);
					toRemove.add(next);
					trymore = it.hasNext();
				} else {
					trymore = false;
				}
			}

			future.removeAll(toRemove);

		} else {
			queue_empty = true;
			running = false;
			printMessage("Simulation: No more future events");
		}

		return queue_empty;
	}

	/**
	 * Internal method used to stop the simulation. This method should
	 * <b>not</b> be used directly.
	 */
	public static void runStop() {
		printMessage("Simulation completed.");
	}

	/**
	 * 同pause相同
	 * Used to hold an entity for some time.
	 *
	 * @param src the src
	 * @param delay the delay
	 */
	public static void hold(int src, long delay) {
		SimEvent e = new SimEvent(SimEvent.HOLD_DONE, clock + delay, src);
		future.addEvent(e);
		entities.get(src).setState(SimEntity.HOLDING);
	}

	/**
	 * 用于实体挂起,实体中的pause方法会调用此方法
	 * 该方法建立事件,加入future中,设置实体状体
	 * ???为什么直接设置实体状态,不是应该是该实体收到该事件之后才挂起吗??
	 * 回答:事件作用是在延迟时间到达后,从新启动该实体
	 * Used to pause an entity for some time.
	 *
	 * @param src the src
	 * @param delay the delay
	 */
	public static void pause(int src, double delay) {
		SimEvent e = new SimEvent(SimEvent.HOLD_DONE, clock + delay, src);
		future.addEvent(e);
		entities.get(src).setState(SimEntity.HOLDING);
	}

	/**
	 * send过程:生成event对象,加入future Queue中,event对象中含有源地址,目标地址
	 * 和事件的其他信息。
	 * Used to send an event from one entity to another.
	 *
	 * @param src the src
	 * @param dest the dest
	 * @param delay the delay
	 * @param tag the tag
	 * @param data the data
	 */
	public static void send(int src, int dest, double delay, int tag, Object data) {
		if (delay < 0) {
			throw new IllegalArgumentException("Send delay can't be negative.");
		}

		SimEvent e = new SimEvent(SimEvent.SEND, clock + delay, src, dest, tag, data);
		future.addEvent(e);
	}
	
	/**
	 * Used to send an event from one entity to another, with priority in the queue.
	 *
	 * @param src the src
	 * @param dest the dest
	 * @param delay the delay
	 * @param tag the tag
	 * @param data the data
	 */
	public static void sendFirst(int src, int dest, double delay, int tag, Object data) {
		if (delay < 0) {
			throw new IllegalArgumentException("Send delay can't be negative.");
		}

		SimEvent e = new SimEvent(SimEvent.SEND, clock + delay, src, dest, tag, data);
		future.addEventFirst(e);
	}

	/**
	 * Sets an entity's state to be waiting. The predicate used to wait for an event
	 * is now passed to Sim_system. Only events that satisfy the predicate will be
	 * passed to the entity. This is done to avoid unnecessary context switches.
	 *
	 * @param src the src
	 * @param p the p
	 */
	public static void wait(int src, Predicate p) {
		entities.get(src).setState(SimEntity.WAITING);
		if (p != SIM_ANY) {
			// If a predicate has been used store it in order to check it
			waitPredicates.put(src, p);
		}
	}

	/**
	 * 队列中事件满足:目的地=d,谓词满足p的事件个数
	 * Checks if events for a specific entity are present in the deferred event queue.
	 *
	 * @param d the d
	 * @param p the p
	 *
	 * @return the int
	 */
	public static int waiting(int d, Predicate p) {
		int count = 0;
		SimEvent event;
		Iterator<SimEvent> iterator = deferred.iterator();
		while (iterator.hasNext()) {
			event = iterator.next();
			if ((event.getDestination() == d) && (p.match(event))) {
				count++;
			}
		}
		return count;
	}

	/**
	 * 选择第一个满足src(目的地)和谓词p条件的事件,并把它从队列中移走
	 * Selects an event matching a predicate.
	 *
	 * @param src the src
	 * @param p the p
	 *
	 * @return the sim event
	 */
	public static SimEvent select(int src, Predicate p) {
		SimEvent ev = null;
		Iterator<SimEvent> iterator = deferred.iterator();
		while (iterator.hasNext()) {
			ev = iterator.next();
			if (ev.getDestination() == src && p.match(ev)) {
				iterator.remove();
				break;
			}
		}
		return ev;
	}

	/**
	 * Removes an event from the event queue.
	 *
	 * @param src the src
	 * @param p the p
	 *
	 * @return the sim event
	 */
	public static SimEvent cancel(int src, Predicate p) {
		SimEvent ev = null;
		Iterator<SimEvent> iter = future.iterator();
		while (iter.hasNext()) {
			ev = iter.next();
			if (ev.getSource() == src && p.match(ev)) {
				iter.remove();
				break;
			}
		}

		return ev;
	}

	/**
	 * Removes all events that match a given predicate from the future event queue
	 * returns true if at least one event has been cancelled; false otherwise.
	 *
	 * @param src the src
	 * @param p the p
	 *
	 * @return true, if successful
	 */
	public static boolean cancelAll(int src, Predicate p) {
		SimEvent ev = null;
		int previousSize = future.size();
		Iterator<SimEvent> iter = future.iterator();
		while (iter.hasNext()) {
			ev = iter.next();
			if (ev.getSource() == src && p.match(ev)) {
				iter.remove();
			}
		}
		return previousSize < future.size();
	}

	//
	// Private internal methods
	//

	/**
	 * Processes an event.处理事件
	 *
	 * @param e the e
	 */
	private static void processEvent(SimEvent e) {
		int dest, src;
		SimEntity dest_ent;
		// Update the system's clock
		if (e.eventTime() < clock) {
			//此时仿真系统的时钟回拨,有可能使事件执行顺序变化
			throw new IllegalArgumentException("Past event detected.");
		}
		clock = e.eventTime();

		// Ok now process it
		switch (e.getType()) {
			case SimEvent.ENULL:
				throw new IllegalArgumentException("Event has a null type.");

			case SimEvent.CREATE:
				SimEntity newe = (SimEntity) e.getData();
				addEntityDynamically(newe);
				break;

			case SimEvent.SEND:
				// Check for matching wait
				dest = e.getDestination();
				if (dest < 0) {
					throw new IllegalArgumentException(
							"Attempt to send to a null entity detected.");
				} else {
					int tag = e.getTag();
					dest_ent = entities.get(dest);
					/**
					 * 实体处于waiting状态时候,通过event事件可以叫醒
					 * 处于waiting状态的实体在waitPredicates中可能纯在谓词
					 * 只有满足此谓词的事件才可以叫醒
					 * 运行状态的实体没有谓词
					 */
					if (dest_ent.getState() == SimEntity.WAITING) {
						
						Integer destObj = Integer.valueOf(dest);
						Predicate p = waitPredicates.get(destObj);
						if ((p == null) || (tag == 9999) || (p.match(e))) {
							dest_ent.setEventBuffer((SimEvent) e.clone());
							dest_ent.setState(SimEntity.RUNNABLE);
							waitPredicates.remove(destObj);
						} else {
							deferred.addEvent(e);
						}
					} else {
						deferred.addEvent(e);
					}
				}
				break;

			case SimEvent.HOLD_DONE:
				src = e.getSource();
				if (src < 0) {
					throw new IllegalArgumentException("Null entity holding.");
				} else {
					entities.get(src).setState(SimEntity.RUNNABLE);
				}
				break;

			default:
				break;
		}
	}

	/**
	 * 启动entities中所有实体
	 * Internal method used to start the simulation. This method should
	 * <b>not</b> be used by user simulations.
	 */
	public static void runStart() {
		running = true;
		// Start all the entities
		for (SimEntity ent : entities) {
			ent.startEntity();
		}

		printMessage("Entities started.");
	}

	/**
	 * Check if the simulation is still running. This method should be used by
	 * entities to check if they should continue executing.
	 *
	 * @return  if the simulation is still running,
	 *  otherwise
	 */
	public static boolean running() {
		return running;
	}

	/**
	 * This method is called if one wants to pause the simulation.
	 *
	 * @return true, if successful
	 * otherwise.
	 */
	public static boolean pauseSimulation() {
		paused = true;
		return paused;
	}

	/**
	 * 终止仿真一定时间
	 * This method is called if one wants to pause the simulation at a given
	 * time.
	 *
	 * @param time the time at which the simulation has to be paused
	 * @return true, if successful
	 * otherwise.
	 */
	public static boolean pauseSimulation(long time) {
		if (time <= clock) {
			return false;
		} else {
			pauseAt = time;
		}
		return true;
	}

	/**
	 * 恢复实体
	 * This method is called if one wants to resume the simulation that has
	 * previously been paused.
	 *
	 * @return if the simulation has been restarted or or
	 *  otherwise.
	 */
	public static boolean resumeSimulation() {
		paused = false;

		if (pauseAt <= clock) {
			pauseAt = -1;
		}

		return !paused;
	}

	/**
	 * 仿真运行
	 * Start the simulation running. This should be called after all the
	 * entities have been setup and added, and their ports linked.
	 *
	 * @return the double last clock value
	 */
	public static double run() {
		if (!running) {
			//启动entities中所有实体
			runStart();
		}
		while (true) {
			//一个一个时刻运行
			if (runClockTick() || abruptTerminate) {
				break;
			}

			if (pauseAt != -1 && ((future.size() > 0 && clock <= pauseAt && pauseAt <= future.iterator().next().eventTime()) || future.size() == 0 && pauseAt <= clock)) {
				pauseSimulation();
				clock = pauseAt;
			}

			while (paused) {
				try {
					Thread.sleep(100);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}

		double clock = clock();

		finishSimulation();
		runStop();

		return clock;
	}

	/**
	 * 仿真结束,置对象为空
	 * Internal method that allows the entities to terminate. This method should
	 * <b>not</b> be used in user simulations.
	 */
	public static void finishSimulation() {
		// Allow all entities to exit their body method
		//非突然中断允许实体处理完剩下的event
		if (!abruptTerminate) {
			for (SimEntity ent : entities) {
				if (ent.getState() != SimEntity.FINISHED) {
					ent.run();
				}
			}
		}

		for (SimEntity ent : entities) {
			ent.shutdownEntity();
		}

		// reset all static variables
		// Private data members
		entities = null;
		entitiesByName = null;
		future = null;
		deferred = null;
		clock = 0L;
		running = false;

		waitPredicates = null;
		paused = false;
		pauseAt = -1;
		abruptTerminate = false;
	}

	/**
	 * Abruptally terminate.
	 */
	public static void abruptallyTerminate() {
		abruptTerminate = true;
	}

	/**
	 * Prints a message about the progress of the simulation.
	 *
	 * @param message the message
	 */
	private static void printMessage(String message) {
		Log.printLine(message);
	}

	/**
	 * Checks if is paused.
	 *
	 * @return true, if is paused
	 */
	public static boolean isPaused() {
		return paused;
	}

}

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐