/* Cyclops
 * FER - SPVP
 * Fakultet elektrotehnike i racunarstva (http://www.fer.hr/)
 * Unska 3, 10000 Zagreb, Hrvatska
 * (c) 2001 FER, Zagreb.
 */

//______________________________________________________________________________________________________

import java.applet.Applet;
import java.util.*;
import java.awt.*;
import java.awt.event.*;
import hr.fer.zesoi.cyclops.*;

//______________________________________________________________________________________________________

/**
 * Cyclops Simulator Applet.
 * @author Darko Vasić
 * @author Tomislav Petković
 * @author Zvonko Kostanjčar
 * @version 0.001 11-06-2001
 */
// TODO add comments
public
class Simulation
extends Applet
implements ActionListener, ItemListener
{
    /** Panel for network display. */
    NetworkSpacePanel network_panel;

    /** Control panel. */
    Panel control_panel;

    /* Unicode values for some letters:
     * Ć 0106 ć 0107 Č 010c č 010d ž 017d   017e
     *   0160 š 0161 Đ 0110 đ 0111
     * Usage is \ uxxxx, where xxxx stands for unicode code.
     */

    /** Traceroute control. */
    Button traceroute = new Button("Put");

    /** Traceroute dialog. */
    TracerouteDialog traceroute_dialog = null;

    /** Add line control. */
    Button add_line = new Button("Dodaj liniju");

    /** Add line dialog. */
    AddLineDialog add_line_dialog = null;

    /** Delete line control. */
    Button delete_line = new Button("Obri\u0161i liniju");

    /** Delete line control dialog. */
    DeleteLineDialog delete_line_dialog = null;

    /** Add node control. */
    Button add_node = new Button("Dodaj \u010dvor");

    /** Add node dialog. */
    AddNodeDialog add_node_dialog = null;

    /** Delete node control.  */
    Button delete_node = new Button("Obri\u0161i \u010dvor");

    /** Delete node dialog. */
    DeleteNodeDialog delete_node_dialog = null;

    /** Start/stop simulation control. */
    Button start_stop_simulation = new Button("Pokreni");

    /** All packets visibilty control. */
    Checkbox all_packets = new Checkbox("Svi paketi");

    /** Line capacity visibility control. */
    Checkbox line_capacities = new Checkbox("Kapaciteti linija");

    /**
     * Applet initialization. Creates controls and initializes
     * network from parameters.
     */
    public void init ()
    {
	setLayout(new BorderLayout());
	network_panel = new NetworkSpacePanel(this);
	control_panel = new Panel();
	network_panel.setName("Network space interface");
	add("Center", network_panel);
	add("South", control_panel);

	control_panel.add(traceroute);
	control_panel.add(add_node);
	control_panel.add(delete_node);
	control_panel.add(add_line);
	control_panel.add(delete_line);
	control_panel.add(start_stop_simulation);
	control_panel.add(all_packets);
	control_panel.add(line_capacities);

	traceroute.addActionListener(this);
	add_node.addActionListener(this);
	delete_node.addActionListener(this);
	add_line.addActionListener(this);
	delete_line.addActionListener(this);
	start_stop_simulation.addActionListener(this);
	all_packets.addItemListener(this);
	line_capacities.addItemListener(this);

	/* Parse input parameters. */
	Node first;
	Node second;
	int i;
	int j;
	int capacity;
	String network = getParameter("network");
	/* Parse input network configuration. */
	if (null != network)
	    {
		StringTokenizer tokenizer = new StringTokenizer(network, ",");
		while (tokenizer.hasMoreTokens())
		    {
			String connection = tokenizer.nextToken();
			i = connection.indexOf('-');
			if (0 < i)
			    {
				capacity = 10;
				j = connection.indexOf('/');
				if (0 < j)
				    {
					capacity = Integer.valueOf(connection.substring(j+1)).intValue();
					connection = connection.substring(0,j);
				    }
				/* Add nodes and connections to network. */
				first = network_panel.addNode(connection.substring(0, i));
				second = network_panel.addNode(connection.substring(i + 1));
				network_panel.addLine(first, second, capacity);
			    }
			/* if */
		    }
		/* while */
	    }
	/* if */
	String packets = getParameter("dummypackets");
	/* Parse dummy packets input. */
	if (null != packets)
	    {
		i = packets.indexOf(',');
		if (0 < i)
		    {
			int ttl = Integer.valueOf(packets.substring(i+1)).intValue();
			int n = Integer.valueOf(packets.substring(0,i)).intValue();
			network_panel.addDummyPackets(n, ttl);
		    }
	    }
	else if (null != network)
	    {
		network_panel.addDummyPackets(40, -1);
	    }
	/* else */
	String route = getParameter("route");
	/* Parse initial route. */
	if (null != route)
	    {
		i = route.indexOf('-');
		if (0 < i)
		    {
			network_panel.tracePackets(route.substring(0,i),
						   route.substring(i+1)
						   );
		    }
	    }
	/* if */
    }
    /* init */

    /**
     * Applet destroy method. Simulation is stopped.
     */
    public void destroy ()
    {
	network_panel.endSimulation();
	remove(network_panel);
	remove(control_panel);
    }
    /* destroy */

    /**
     * Start method. Resumes screen updating.
     */
    public void start()
    {
	network_panel.start();
    }
    /* start */

    /**
     * Stop method. Stops screen updating.
     */
    public void stop()
    {
	network_panel.stop();
    }
    /* stop */

    /**
     * Action events handler.
     */
    public void actionPerformed (ActionEvent event)
    {
	Object source = event.getSource();
	String command = event.getActionCommand();
	int modifier = event.getModifiers();

	/* traceroute event */
	if (source == traceroute)
	    {
		if (null == traceroute_dialog)
		    {
			traceroute_dialog = new TracerouteDialog(this);
		    }
	    }
	/* traceroute dialog event */
	if (source == traceroute_dialog)
	    {
		if (command.equals("OK"))
		    {
			network_panel.stopSimulation();
			network_panel.tracePackets(traceroute_dialog.left_name,
						   traceroute_dialog.right_name
						   );
			String name = start_stop_simulation.getLabel();
			if (name.equals("Zaustavi"))
			    {
				network_panel.startSimulation();
			    }
		    }
		traceroute_dialog = null;
	    }
	/* add_line event */
	if (source == add_line)
	    {
		if (null == add_line_dialog)
		    {
			add_line_dialog = new AddLineDialog(this);
		    }
	    }
	/* add_line_dialog event */
	if (source == add_line_dialog)
	    {
		if (command.equals("OK"))
		    {
			network_panel.stopSimulation();
			Node first = network_panel.addNode(add_line_dialog.left_name);
			Node second = network_panel.addNode(add_line_dialog.right_name);
			network_panel.addLine(first, second, add_line_dialog.capacity);
			String name = start_stop_simulation.getLabel();
			if (name.equals("Zaustavi"))
			    {
				network_panel.startSimulation();
			    }
		    }
		add_line_dialog = null;
	    }
	/* add_node event */
	if (source == add_node)
	    {
		if (null == add_node_dialog)
		    {
			add_node_dialog = new AddNodeDialog(this);
		    }
	    }
	/* add_node_dialog event */
	if (source == add_node_dialog)
	    {
		if (command.equals("OK"))
		    {
			network_panel.stopSimulation();
			Node new_node = network_panel.addNode(add_node_dialog.node_name);
			String name = start_stop_simulation.getLabel();
			if (name.equals("Zaustavi"))
			    {
				network_panel.startSimulation();
			    }
		    }
		add_node_dialog = null;
	    }
	/* delete_line event */
	if (source == delete_line)
	    {
		if (null == delete_line_dialog)
		    {
			delete_line_dialog = new DeleteLineDialog(this);
		    }
	    }
	/* delete_line_dialog event */
	if (source == delete_line_dialog)
	    {
		if (command.equals("OK"))
		    {
			network_panel.stopSimulation();
			Line deleted = network_panel.deleteLine(delete_line_dialog.left_name,
								delete_line_dialog.right_name
								);
			String name = start_stop_simulation.getLabel();
			if (name.equals("Zaustavi"))
			    {
				network_panel.startSimulation();
			    }
		    }
		delete_line_dialog = null;
	    }
	/* delete_node event */
	if (source == delete_node)
	    {
		if (null == delete_node_dialog)
		    {
			delete_node_dialog = new DeleteNodeDialog(this);
		    }
	    }
	/* delete_node_dialog event */
	if (source == delete_node_dialog)
	    {
		if (command.equals("OK"))
		    {
			network_panel.stopSimulation();
			Node deleted = network_panel.deleteNode(delete_node_dialog.node_name);
			String name = start_stop_simulation.getLabel();
			if (name.equals("Zaustavi"))
			    {
				network_panel.startSimulation();
			    }
		    }
		delete_node_dialog = null;
	    }
	/* start_stop_simulation event */
	if (source == start_stop_simulation)
	    {
		String name = start_stop_simulation.getLabel();
		if (name.equals("Pokreni"))
		    {
			start_stop_simulation.setLabel("Zaustavi");
			network_panel.startSimulation();
		    }
		else
		    {
			start_stop_simulation.setLabel("Pokreni");
			network_panel.stopSimulation();
		    }
	    }
    }
    /* actionPreformed*/

    /**
     * Item events handler.
     */
    public void itemStateChanged (ItemEvent event)
    {
	Object source;
	boolean on;

	source = event.getSource();
	on = event.getStateChange() == ItemEvent.SELECTED;
	if (source == all_packets)
	    {
		network_panel.all_packets = on;
	    }
	if (source ==line_capacities)
	    {
		network_panel.show_line_capacities = on;
	    }
    }
    /* itemStateChanged */

    /**
     * Gets applet information.
     */
    public String getAppletInfo ()
    {
	return "Cyclops simulator\nFER/SPVP 2001\nD. Vasić, T. Petković, Z. Kostanjčar";
    }
}
/* Simulation */

//______________________________________________________________________________________________________

/**
 * NetworkSpacePanel class. This is class for drawing
 * entire network.
 */
class NetworkSpacePanel
extends Panel
implements Runnable, MouseListener, MouseMotionListener
{

    /** Simulator thread. */
    CyclopsSimulator cyclops = new CyclopsSimulator();

    /** Simulator applet. */
    Simulation simulation_applet;

    /** Node object. */
    Node currently_manipulated;

    /** Current thread. */
    Thread simulator;

    /** All packets visibility flag. */
    boolean all_packets;

    /** Line capacity visibility flag. */
    boolean show_line_capacities;

    /**
     * Default constructor.
     */
    public NetworkSpacePanel (Simulation simulation_applet)
    {
	this.simulation_applet = simulation_applet;
	addMouseListener(this);
	addMouseMotionListener(this);
	cyclops.start();
	cyclops.setName("Cyclops simulator");
    }
    /* NetworkSpacePanel*/

    /**
     * Adds node to network. Node is identified by its name.
     * If node already exists, method will return reference of
     * existing node, otherwise a new node will be created.
     * @param name Node name.
     * @return Returns node reference.
     */
    public Node addNode (String name)
    {
	Node new_node;
	new_node = cyclops.findNode(name);
	if (new_node == null)
	    {
		new_node = new Node(name);
		cyclops.addNode(new_node);
	    }
	return new_node;
    }
    /* addNode */

    /**
     * Deletes node from network. Node is identified by its name.
     * If node already exists, method will return reference of
     * existing node. Otherwise null reference will be returned.
     * @param name Node name.
     * @return Returns node reference.
     */
    public Node deleteNode (String name)
    {
	Node removed_node;
	removed_node = cyclops.deleteNode(name);
	return removed_node;
    }
    /* deleteNode */

    /**
     * Adds dummy packets.
     * @param number Number of packets.
     * @param time_to_live TTL.
     */
    public void addDummyPackets(int number, int time_to_live)
    {
	cyclops.addDummyPackets(number, time_to_live);
    }
    /* addDummyPackets */
      
    /**
     * Trace packets.
     * @param start_node Name of a source node.
     * @param end_node Name of a destination node.
     */
    public void tracePackets(String start_node, String end_node)
    {
	if (!start_node.equals(end_node))
	    {
		cyclops.tracePackets(start_node, end_node);
	    }
    }
    /* tracePackets */

    /**
     * Adds line to network. Symmetric line is created.
     * @param first First node referenece.
     * @param second Second node reference.
     * @param capacity Line capacity.
     */
    public void addLine (Node first, Node second, int capacity)
    {
	Line new_line = new Line(first, second, capacity);
	cyclops.addLine(new_line);
    }
    /* addLine */

    /**
     * Deletes line from network.
     * @param first First node name.
     * @param second Second node name.
     * @return Returns line reference.
     */
    public Line deleteLine(String first, String second)
    {
	Line deleted;
	deleted = cyclops.deleteLine(first, second);
	return deleted;
    }
    /* deleteLine */

    /**
     * Run method. Only updates the screen.
     */
    public void run()
    {
	Thread me;

	me = Thread.currentThread();
	while (simulator == me)
	    {
		repaint();
		try
		    {
			Thread.sleep(100);
		    }
		catch (InterruptedException exception)
		    {
			break;
		    }
	    }
    }
    /* run */

    Image off_screen;
    Dimension off_screen_size;
    Graphics off_graphics;

    final Color node_color = new Color(250, 220, 100);
    final Color line_color = Color.black;
    final Color left_packet_color = new Color(250, 200, 80);
    final Color right_packet_color = new Color(250, 240, 120);

    /**
     * Updates the screen.
     * @param g Graphics reference.
     */
    public synchronized void update (Graphics g)
    {
	Dimension d = getSize();
	if ((null == off_screen) ||
	    (d.width != off_screen_size.width) ||
	    (d.height != off_screen_size.height)
	    )
	    {
		off_screen = createImage(d.width, d.height);
		off_screen_size = d;
		off_graphics = off_screen.getGraphics();
		off_graphics.setFont(getFont());
	    }
	off_graphics.setColor(getBackground());
	off_graphics.fillRect(0, 0, d.width, d.height);
	FontMetrics metrics = off_graphics.getFontMetrics();
	cyclops.paint(off_graphics, metrics,
		      node_color, line_color,
		      left_packet_color, right_packet_color, Color.red,
		      show_line_capacities, all_packets
		      );
	g.drawImage(off_screen, 0, 0, null);
    }
    /* update */

    /**
     * Empty event.
     * @param event Mouse event.
     */
    public void mouseClicked (MouseEvent event)
    {
    }
    /* mouseClicked */

    /**
     * Findes closes node to mouse pointer and selects it.
     * @param event Mouse event.
     */
    public void mousePressed (MouseEvent event)
    {
	double best_distance = Double.MAX_VALUE;
	double distance;
	int n = cyclops.numberOfNodes();
	int x = event.getX();
	int y = event.getY();
	Node current_node;
	int i;
	for (i=0; i!=n; i++)
	    {
		current_node = cyclops.nodeAt(i);
		distance = (x - current_node.getXCoordinate())
		    * (x - current_node.getXCoordinate())
		    + (y - current_node.getYCoordinate())
		    * (y - current_node.getYCoordinate());
		if (distance < best_distance)
		    {
			currently_manipulated = current_node;
			best_distance = distance;
		    }
	    }
	currently_manipulated.setCoordinates(x, y);
	repaint();
	event.consume();
    }
    /* mousePressed */

    /**
     * Releases hold on node and sets new screen coordinates.
     * @param event Mouse event.
     */
    public void mouseReleased (MouseEvent event)
    {
	currently_manipulated.setCoordinates(event.getX(), event.getY());
	currently_manipulated = null;
	repaint();
	event.consume();
    }
    /* mouseReleased */

    /**
     * Empty event.
     * @param event Mouse event.
     */
    public void mouseEntered (MouseEvent event)
    {
    }
    /* mouseEntered */

    /**
     * Empty event.
     * @param event Mouse event.
     */
    public void mouseExited (MouseEvent event)
    {
    }
    /* mouseExited */

    /**
     * Moves node.
     * @param event Mouse event.
     */
    public void mouseDragged (MouseEvent event)
    {
	currently_manipulated.setCoordinates(event.getX(), event.getY());
	repaint();
	event.consume();
    }
    /* mouseDragged */

    /**
     * Empty event.
     * @param event Mouse event.
     */
    public void mouseMoved (MouseEvent event)
    {
    }
    /* mouseMoved */

    /**
     * Starts thread. 
     */
    public void start ()
    {
	simulator = new Thread(this);
	simulator.start();
    }
    /* start */

    /**
     * Stops thread.
     */
    public void stop ()
    {
	simulator = null;
    }
    /* stop */

    /**
     * Starts/resumes simulation.
     */
    public void startSimulation ()
    {
	cyclops.startSimulation();
    }
    /* startSimulation */

    /**
     * Stops/suspends simulation.
     */
    public void stopSimulation ()
    {
	cyclops.stopSimulation();
    }
    /* stopSimulation */

    /**
     * Ends simulation.
     */
    public void endSimulation ()
    {
	cyclops.endSimulation();
    }
    /* endSimulation */
}
/* NetworkSpacePanel */

//______________________________________________________________________________________________________

/**
 * Line add dialog. For each line both node ends
 * must be defined. If node does not exist, new one
 * with defined name is created.
 */
class AddLineDialog
implements ActionListener
{

    /** Action listener. */
    ActionListener action_listener;

    /** Add line dialog box. */
    Dialog add_line;

    /** Add line OK button. */
    Button button_ok;

    /** Add line Cancel button. */
    Button button_cancel;

    /** Left node name field. */
    TextField left_field;

    /** Left node name. */
    String left_name;

    /** Right node name field. */
    TextField right_field;

    /** Right node name. */
    String right_name;

    /** Capacity field. */
    TextField capacity_field;

    /** Capacity. */
    int capacity;

    /** Dummy frame required to aviod null-parent exception. */
    Frame dummy;

    /**
     * Default constructor. Reference to network panel is required.
     * @param action_listener Reference to action listener.
     */
    public AddLineDialog (ActionListener action_listener)
    {
	this.action_listener = action_listener;

	dummy = new Frame();
	add_line = new Dialog(dummy, "Dodaj liniju");
	button_ok = new Button("U redu");
	button_cancel = new Button("Odustani");
	left_field = new TextField("ime", 30);
	right_field = new TextField("ime", 30);
	capacity_field = new TextField("20", 30);

	Label left_label = new Label("Lijevi \u010dvor", Label.RIGHT);
	Label right_label = new Label("Desni \u010dvor", Label.RIGHT);
	Label capacity_label = new Label("Kapacitet", Label.RIGHT);

	add_line.setLayout(new BorderLayout());
        add_line.setLayout(new GridLayout(4,2));
	add_line.add(left_label);
	add_line.add(left_field);
	add_line.add(right_label);
	add_line.add(right_field);
	add_line.add(capacity_label);
	add_line.add(capacity_field);
	add_line.add(button_ok);
	add_line.add(button_cancel);

	right_field.addActionListener(this);
	left_field.addActionListener(this);
	capacity_field.addActionListener(this);
	button_ok.addActionListener(this);
	button_cancel.addActionListener(this);

	add_line.pack();
	add_line.setResizable(false);
	add_line.show();
    }

    /**
     * Action handler. Wait for OK or Cancel button and
     * then reads input and terminates dialog.
     */
    public void actionPerformed (ActionEvent event)
    {
	Object source = event.getSource();

	/*  left_field event */
	if (source == left_field)
	    {
		left_name = left_field.getText();
	    }
	/*  right_field event */
	if (source == right_field)
	    {
		right_name = right_field.getText();
	    }
	/*  capacity event */
	if (source == capacity_field)
	    {
		capacity = Integer.valueOf(capacity_field.getText()).intValue();
	    }
	/*  button_ok event */
	if (source == button_ok)
	    {
		left_name = left_field.getText();
		right_name = right_field.getText();
		capacity = Integer.valueOf(capacity_field.getText()).intValue();
		add_line.dispose();
		if (left_name.equals(right_name))
		    {
			action_listener.actionPerformed(new ActionEvent(this, 1, "Cancel"));
		    }
		else
		    {
			action_listener.actionPerformed(new ActionEvent(this, 1, "OK"));
		    }
	    }
	/*  button_cancel event */
	if (source == button_cancel)
	    {
		add_line.dispose();
		action_listener.actionPerformed(new ActionEvent(this, 0, "Cancel"));
	    }
    }
    /* actionPreformed*/

}
/* AddLineDialog */

//______________________________________________________________________________________________________

/**
 * Add node dialog. If node with given name
 * does not exist, new one with defined name is created.
 */
class AddNodeDialog
implements ActionListener
{

    /** Action listener. */
    ActionListener action_listener;

    /** Add node dialog box. */
    Dialog add_node;

    /** Add node OK button. */
    Button button_ok;

    /** Add node Cancel button. */
    Button button_cancel;

    /** Node name field. */
    TextField node_field;

    /** Node name. */
    String node_name;

    /** Dummy frame required to aviod null-parent exception. */
    Frame dummy;

    /**
     * Default constructor. Reference to network panel is required.
     * @param action_listener Reference to action listener.
     */
    public AddNodeDialog (ActionListener action_listener)
    {
	this.action_listener = action_listener;

	dummy = new Frame();
	add_node = new Dialog(dummy, "Dodaj \u010dvor");
	button_ok = new Button("U redu");
	button_cancel = new Button("Odustani");
	node_field = new TextField("ime", 30);

	Label node_label = new Label("Ime \u010dvora", Label.RIGHT);

	add_node.setLayout(new BorderLayout());
        add_node.setLayout(new GridLayout(2,2));
	add_node.add(node_label);
	add_node.add(node_field);
	add_node.add(button_ok);
	add_node.add(button_cancel);

	node_field.addActionListener(this);
	button_ok.addActionListener(this);
	button_cancel.addActionListener(this);

	add_node.pack();
	add_node.setResizable(false);
	add_node.show();
    }

    /**
     * Action handler. Wait for OK or Cancel button and
     * then reads input and terminates dialog.
     */
    public void actionPerformed (ActionEvent event)
    {
	Object source = event.getSource();

	/*  node_field event */
	if (source == node_field)
	    {
		node_name = node_field.getText();
	    }
	/*  button_ok event */
	if (source == button_ok)
	    {
		node_name = node_field.getText();
		add_node.dispose();
		action_listener.actionPerformed(new ActionEvent(this, 1, "OK"));
	    }
	/*  button_cancel event */
	if (source == button_cancel)
	    {
		add_node.dispose();
		action_listener.actionPerformed(new ActionEvent(this, 0, "Cancel"));
	    }
    }
    /* actionPreformed*/

}
/* AddNodeDialog */

//______________________________________________________________________________________________________

/**
 * Delete line dialog. For each line both node ends
 * must be defined, otherwise line is not uniquely indentifiable.
 */
class DeleteLineDialog
implements ActionListener
{

    /** Action listener. */
    ActionListener action_listener;

    /** Add line dialog box. */
    Dialog delete_line;

    /** Add line OK button. */
    Button button_ok;

    /** Add line Cancel button. */
    Button button_cancel;

    /** Left node name field. */
    TextField left_field;

    /** Left node name. */
    String left_name;

    /** Right node name field. */
    TextField right_field;

    /** Right node name. */
    String right_name;

    /** Dummy frame required to aviod null-parent exception. */
    Frame dummy;

    /**
     * Default constructor. Reference to network panel is required.
     * @param action_listener Reference to action listener.
     */
    public DeleteLineDialog (ActionListener action_listener)
    {
	this.action_listener = action_listener;

	dummy = new Frame();
	delete_line = new Dialog(dummy, "Obri\u0161i liniju");
	button_ok = new Button("U redu");
	button_cancel = new Button("Odustani");
	left_field = new TextField("ime", 30);
	right_field = new TextField("ime", 30);

	Label left_label = new Label("Lijevi \u010dvor", Label.RIGHT);
	Label right_label = new Label("Desni \u010dvor", Label.RIGHT);

	delete_line.setLayout(new BorderLayout());
        delete_line.setLayout(new GridLayout(3,2));
	delete_line.add(left_label);
	delete_line.add(left_field);
	delete_line.add(right_label);
	delete_line.add(right_field);
	delete_line.add(button_ok);
	delete_line.add(button_cancel);

	right_field.addActionListener(this);
	left_field.addActionListener(this);
	button_ok.addActionListener(this);
	button_cancel.addActionListener(this);

	delete_line.pack();
	delete_line.setResizable(false);
	delete_line.show();
    }

    /**
     * Action handler. Wait for OK or Cancel button and
     * then reads input and terminates dialog.
     */
    public void actionPerformed (ActionEvent event)
    {
	Object source = event.getSource();

	/*  left_field event */
	if (source == left_field)
	    {
		left_name = left_field.getText();
	    }
	/*  right_field event */
	if (source == right_field)
	    {
		right_name = right_field.getText();
	    }
	/*  capacity event */
	if (source == button_ok)
	    {
		left_name = left_field.getText();
		right_name = right_field.getText();
		delete_line.dispose();
		action_listener.actionPerformed(new ActionEvent(this, 1, "OK"));
	    }
	/*  button_cancel event */
	if (source == button_cancel)
	    {
		delete_line.dispose();
		action_listener.actionPerformed(new ActionEvent(this, 0, "Cancel"));
	    }
    }
    /* actionPreformed*/

}
/* DeleteLineDialog */

//______________________________________________________________________________________________________

/**
 * Delete node dialog. If node with given name
 * does not exist, amazingly, nothing happenes.
 */
class DeleteNodeDialog
implements ActionListener
{

    /** Action listener. */
    ActionListener action_listener;

    /** Add node dialog box. */
    Dialog delete_node;

    /** Add node OK button. */
    Button button_ok;

    /** Add node Cancel button. */
    Button button_cancel;

    /** Node name field. */
    TextField node_field;

    /** Node name. */
    String node_name;

    /** Dummy frame required to aviod null-parent exception. */
    Frame dummy;

    /**
     * Default constructor. Reference to network panel is required.
     * @param action_listener Reference to action listener.
     */
    public DeleteNodeDialog (ActionListener action_listener)
    {
	this.action_listener = action_listener;

	dummy = new Frame();
	delete_node = new Dialog(dummy, "Obri\u0161i \u010dvor");
	button_ok = new Button("U redu");
	button_cancel = new Button("Odustani");
	node_field = new TextField("ime", 30);

	Label node_label = new Label("Ime \u010dvora", Label.RIGHT);

	delete_node.setLayout(new BorderLayout());
        delete_node.setLayout(new GridLayout(2,2));
	delete_node.add(node_label);
	delete_node.add(node_field);
	delete_node.add(button_ok);
	delete_node.add(button_cancel);

	node_field.addActionListener(this);
	button_ok.addActionListener(this);
	button_cancel.addActionListener(this);

	delete_node.pack();
	delete_node.setResizable(false);
	delete_node.show();
    }

    /**
     * Action handler. Wait for OK or Cancel button and
     * then reads input and terminates dialog.
     */
    public void actionPerformed (ActionEvent event)
    {
	Object source = event.getSource();

	/*  node_field event */
	if (source == node_field)
	    {
		node_name = node_field.getText();
	    }
	/*  button_ok event */
	if (source == button_ok)
	    {
		node_name = node_field.getText();
		delete_node.dispose();
		action_listener.actionPerformed(new ActionEvent(this, 1, "OK"));
	    }
	/*  button_cancel event */
	if (source == button_cancel)
	    {
		delete_node.dispose();
		action_listener.actionPerformed(new ActionEvent(this, 0, "Cancel"));
	    }
    }
    /* actionPreformed*/

}
/* DeleteNodeDialog */

//______________________________________________________________________________________________________

/**
 * Traceroute dialog. For each route both source node and destination
 * node must be defined, otherwise route is not uniquely indentifiable.
 */
class TracerouteDialog
implements ActionListener
{

    /** Action listener. */
    ActionListener action_listener;

    /** Traceroute dialog box. */
    Dialog traceroute;

    /** Traceroute OK button. */
    Button button_ok;

    /** Traceroute Cancel button. */
    Button button_cancel;

    /** Left node name field. */
    TextField left_field;

    /** Left node name. */
    String left_name;

    /** Right node name field. */
    TextField right_field;

    /** Right node name. */
    String right_name;

    /** Dummy frame required to aviod null-parent exception. */
    Frame dummy;

    /**
     * Default constructor. Reference to network panel is required.
     * @param action_listener Reference to action listener.
     */
    public TracerouteDialog (ActionListener action_listener)
    {
	this.action_listener = action_listener;

	dummy = new Frame();
	traceroute = new Dialog(dummy, "Pra\u0107enje paketa");
	button_ok = new Button("U redu");
	button_cancel = new Button("Odustani");
	left_field = new TextField("ime", 30);
	right_field = new TextField("ime", 30);

	Label left_label = new Label("Po\u010detni \u010dvor", Label.RIGHT);
	Label right_label = new Label("Kona\u010dni \u010dvor", Label.RIGHT);

	traceroute.setLayout(new BorderLayout());
        traceroute.setLayout(new GridLayout(3,2));
	traceroute.add(left_label);
	traceroute.add(left_field);
	traceroute.add(right_label);
	traceroute.add(right_field);
	traceroute.add(button_ok);
	traceroute.add(button_cancel);

	right_field.addActionListener(this);
	left_field.addActionListener(this);
	button_ok.addActionListener(this);
	button_cancel.addActionListener(this);

	traceroute.pack();
	traceroute.setResizable(false);
	traceroute.show();
    }

    /**
     * Action handler. Wait for OK or Cancel button and
     * then reads input and terminates dialog.
     */
    public void actionPerformed (ActionEvent event)
    {
	Object source = event.getSource();

	/*  left_field event */
	if (source == left_field)
	    {
		left_name = left_field.getText();
	    }
	/*  right_field event */
	if (source == right_field)
	    {
		right_name = right_field.getText();
	    }
	/*  capacity event */
	if (source == button_ok)
	    {
		left_name = left_field.getText();
		right_name = right_field.getText();
		traceroute.dispose();
		action_listener.actionPerformed(new ActionEvent(this, 1, "OK"));
	    }
	/*  button_cancel event */
	if (source == button_cancel)
	    {
		traceroute.dispose();
		action_listener.actionPerformed(new ActionEvent(this, 0, "Cancel"));
	    }
    }
    /* actionPreformed*/

}
/* TracerouteDialog */

//______________________________________________________________________________________________________

/* Simulation.java ends here. */
