package interfacing;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.text.DecimalFormat;
import java.util.GregorianCalendar;

import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import mapping.data.Server;
import mapping.data.MessageToServer;

/**
 * The JPanel allow you to set availability parameters to each server
 */
public class ServersAvailabilityJPanel extends JPanel implements MouseListener, PropertyChangeListener, KeyListener {

	/**
	 * The serialVersionUID is used to universally identify this version of this
	 * class.
	 */
	private static final long serialVersionUID = -1314942526341209428L;

	/** Names of the columns in jTable (Attributes edited) */
	private String[] columnNames = { "ID", "Hostname" };

	private MainFrame frame;

	/** The view component of the table. */
	private JTable jTable;

	/** The tableModel object of JTable */
	private OurDefaultTableModel tableModel;

	/** The listener of the tableModel */
	private ServersTableModelListener serversTableModelListener;

	/** The scroll pane that the table is put in. */
	private JScrollPane jTableScrollPane;

	/** This main SplitPane that splits this JPanel */
	private JSplitPane splitPane;

	/** The left side of the main splitPane */
	private JScrollPane leftScrollPane;

	/** The right side of the main splitPane */
	private JScrollPane rightScrollPane;

	/** The panel that holds the jTable and its scroll pane */
	private JPanel jTableContainer;

	/** The panel that holds the add and remove buttons. */
	private JPanel buttonsConatainers;

	/** The panel used to construct the message sent to a server. */
	private MessageToServerJPanel messagePanel;

	private JPanel rightJPanel;
	private JPanel serverLabelJPanel;
	private JLabel serverLabel;
	private JLabel serverName;

	/**
	 * This determines whether this Panel receives input from users or not
	 */
	private boolean editable = true;

	/**
	 * 
	 * @param frame
	 *            is the container of this JPanel.
	 * 
	 */
	public ServersAvailabilityJPanel(MainFrame frame) {
		this.frame = frame;

		// Initialize the GUI components
		leftScrollPane = new JScrollPane(); // left side of of splitPane
		rightScrollPane = new JScrollPane(); // right side of of splitPane
		jTable = new JTable(); // jTable component that shows the table
		jTableScrollPane = new JScrollPane(); // The scroll pane where the
		// jTable lives.
		jTableContainer = new JPanel(); // The panel that holds the jTable and
		// its scrollPane
		this.setLayout(new BorderLayout());

		/*--------- Right Panel building --------------*/
		rightJPanel = new JPanel();
		rightJPanel.setLayout(new BorderLayout());

		serverLabelJPanel = new JPanel();
		serverLabel = new JLabel("Server: ");
		serverName = new JLabel();
		serverName.setFont(new Font("", Font.BOLD, 13));
		serverLabelJPanel.add(serverLabel);
		serverLabelJPanel.add(serverName);
		rightJPanel.add(serverLabelJPanel, BorderLayout.NORTH);
		messagePanel = new MessageToServerJPanel(this);
		rightJPanel.add(messagePanel, BorderLayout.CENTER);
		rightScrollPane.setViewportView(rightJPanel);

		splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, leftScrollPane, rightScrollPane);
		splitPane.setDividerLocation(450);

		// Registering the Listener which responsible for validating data and
		// send it the view
		serversTableModelListener = new ServersTableModelListener(this.frame);

		/* Building jTableContainer */
		jTableContainer.setLayout(new GridBagLayout());
		GridBagConstraints gbConstraints = new GridBagConstraints();
		gbConstraints.gridx = 0;
		gbConstraints.gridy = 1;
		gbConstraints.fill = GridBagConstraints.NONE;
		gbConstraints.anchor = GridBagConstraints.NORTH;
		gbConstraints.gridheight = 1;
		gbConstraints.gridwidth = 1;

		jTableScrollPane.setViewportView(jTable); // adding jTable to its
		// scroll pane
		jTableContainer.add(jTableScrollPane, gbConstraints); // add the
		// jTable and
		// its pane to
		// jTableContainer
		gbConstraints.gridy = 0;
		// Building a panel containing + and - buttons
		buttonsConatainers = new JPanel();

		jTableContainer.add(buttonsConatainers, gbConstraints); // add buttons
		// panel and its
		// pane to
		// jTableContainer

		// This segment forces the north alignment of the components
		gbConstraints.weighty = 1.0;
		gbConstraints.fill = GridBagConstraints.BOTH;
		gbConstraints.gridy = 2;
		jTableContainer.add(javax.swing.Box.createVerticalGlue(), gbConstraints);

		leftScrollPane.setViewportView(jTableContainer);
		this.add(splitPane);
		jTable.setGridColor(Color.BLACK);
		jTable.setBackground(new Color(230, 230, 230));

		/* JTable Cosmetic */
		this.fillJTable();
		jTable.getColumnModel().getColumn(0).setPreferredWidth(50);
		jTable.getColumnModel().getColumn(1).setPreferredWidth(250);
		jTable.setDragEnabled(false);

		int h = (1 + jTable.getModel().getRowCount()) * jTable.getRowHeight() + 100;
		this.setPreferredSize(new Dimension(600, h));

		// RIGHT SIDE

		splitPane.addPropertyChangeListener(this);

	}

	/**
	 * This method fill the table model (tableModel) of the corresponding data
	 * from the serversTable object that this JPanel is the view for. The jTable
	 * object is changed correspondingly.
	 */

	public void fillJTable() {
		tableModel = new OurDefaultTableModel(columnNames, 0);
		tableModel.setEditable(false);
		jTable.setModel(tableModel);

		jTable.addKeyListener(this);
		Server server;

		Object[] objects = this.frame.getMapper().getServersTable().keySet().toArray();

		for (int i = 0; i < objects.length; i++) {
			server = this.frame.getMapper().getServer(i + 1);

			String[] s = { server.getIndex() + "", server.getHostName() + "" };
			tableModel.addRow(s);
		}

		jTable.getColumnModel().getColumn(0).setPreferredWidth(20);
		jTable.getColumnModel().getColumn(1).setPreferredWidth(350);

		jTable.addMouseListener(this);

		serversTableModelListener = new ServersTableModelListener(this.frame);
		tableModel.addTableModelListener(serversTableModelListener);

	}

	/**
	 * This method resizes JTable
	 */
	private void reSizeJTable() {
		int rowCount = (1 + jTable.getModel().getRowCount());
		int rowHeight = jTable.getRowHeight();
		int h = rowCount * rowHeight + 5;
		Dimension d = new Dimension(this.splitPane.getDividerLocation() - 10, h);
		jTable.setSize(d);
		jTableContainer.setPreferredSize(d);
		jTableScrollPane.setPreferredSize(d);
		rightJPanel.setPreferredSize(d); // d should be changed
		this.setPreferredSize(new Dimension(500, d.height + 100));
		this.repaint();
	}

	/**
	 * This method refill the JTable with the data when the JPanel is repainted
	 */
	public void repaint() {
		if (this.jTable != null)
			fillJTable();
	}

	public void printModel(OurDefaultTableModel model) {
		for (int i = 0; i < model.getRowCount(); i++) {
			for (int j = 0; j < model.getColumnCount(); j++) {
				System.out.print(model.getValueAt(i, j) + " ");
			}
			System.out.println();
		}
	}

	/**
	 * This method disables input from user
	 */
	public void disableInput() {
		this.editable = false;
		tableModel.setEditable(false);

	}

	/**
	 * This method enable input from user
	 */
	public void enableInput() {
		this.editable = true;
		tableModel.setEditable(true);
		if (editable)
			editable = true;

	}

	/**
	 * 
	 * @return true if some rows are selected in the JTable, false otherwise.
	 */
	public boolean isThereASelection() {
		return (jTable.getSelectedRowCount() > 0);
	}

	/**
	 * This method is invoked by the MessageToServerJPanel objects to notify
	 * this JPanel of the user applying a message to the selection. This method
	 * changes the message to be sent to the server and also regenerate the
	 * artificial failures rates according to the failuresPeriodsMean and
	 * upTimeMean.
	 * 
	 * @param message
	 *            The message to be applied
	 * @param failuresPeriodsMean
	 *            the new failuresPeriodsMean
	 * @param upTimeMean
	 *            the new upTimeMean
	 */
	public void applyMessageAndFillTraces(MessageToServer message, double failuresPeriodsMean, double upTimeMean) {
		if (jTable.getSelectedRow() >= 0 && jTable.getSelectedRow() < this.frame.getMapper().getServersTable().size()) {
			ProgressBarFrame frame = new ProgressBarFrame("Servers", jTable.getSelectedRowCount());

			for (int i = 0; i < jTable.getSelectedRowCount(); i++) {

				frame.changeProgress(i + 1, "Failure trace generations and message was applied to server "
						+ (jTable.getSelectedRows()[i] + 1));
				this.frame.getMapper().getServer(jTable.getSelectedRows()[i] + 1).setAvailabilty(
						message.getAvailability());
				this.frame.getMapper().getServer(jTable.getSelectedRows()[i] + 1).setLastMessageSent(
						(MessageToServer) message.clone());

				// To fill the failure traces
				GregorianCalendar startTime = new GregorianCalendar();
				GregorianCalendar endTime = new GregorianCalendar();
				endTime.add(GregorianCalendar.HOUR, 48);

				this.frame.getMapper().getServer(jTable.getSelectedRows()[i] + 1).getFailureTrace().fillTrace(
						startTime, endTime, failuresPeriodsMean, upTimeMean,
						this.frame.getMapper().getTimeUnitInMinutes());

				System.out.println(message.toString());
			}
		}
	}

	/**
	 * This method is invoked by the MessageToServerJPanel objects to notify
	 * this JPanel of the user applying a message to the selection. This method
	 * changes the message to be sent to the server.
	 * 
	 * @param message
	 *            The message to be applied
	 */
	public void applyMessage(MessageToServer message) {
		if (jTable.getSelectedRow() >= 0 && jTable.getSelectedRow() < this.frame.getMapper().getServersTable().size()) {
			ProgressBarFrame frame = new ProgressBarFrame("Servers", jTable.getSelectedRowCount());

			for (int i = 0; i < jTable.getSelectedRowCount(); i++) {

				frame.changeProgress(i + 1, "Message was applied to server " + (jTable.getSelectedRows()[i] + 1));
				this.frame.getMapper().getServer(jTable.getSelectedRows()[i] + 1).setAvailabilty(
						message.getAvailability());
				this.frame.getMapper().getServer(jTable.getSelectedRows()[i] + 1).setLastMessageSent(
						(MessageToServer) message.clone());

				System.out.println("Message: " + message.toString());
			}
		}
	}

	/**
	 * Used to keep the JTable look nice
	 */
	public void propertyChange(PropertyChangeEvent evt) {
		reSizeJTable();
	}

	/**
	 * This is used to show the corresponding data on the left side when a
	 * Server is clicked
	 */
	public void mouseClicked(MouseEvent e) {
		if (e.getSource() == jTable) {
			if (jTable.getSelectedRow() >= 0
					&& jTable.getSelectedRow() < this.frame.getMapper().getServersTable().size()) {
				this.serverName.setText(this.frame.getMapper().getServersTable().get(jTable.getSelectedRow() + 1)
						.getHostName());
				this.messagePanel.setMessage(this.frame.getMapper().getServer(jTable.getSelectedRow() + 1)
						.getLastMessageSent());
				if (jTable.getSelectedRowCount() > 1) {
					this.serverName.setText("Multiple");
				}
			}
		}
	}

	public void mouseEntered(MouseEvent e) {
	}

	public void mouseExited(MouseEvent e) {
	}

	public void mousePressed(MouseEvent e) {
	}

	public void mouseReleased(MouseEvent e) {
	}

	public void keyPressed(KeyEvent arg0) {

	}

	/**
	 * This is used to show the corresponding data on the left side when a
	 * Server is selected
	 */
	public void keyReleased(KeyEvent e) {
		if (e.getSource() == jTable) {
			if (jTable.getSelectedRow() >= 0
					&& jTable.getSelectedRow() < this.frame.getMapper().getServersTable().size()) {
				this.serverName.setText(this.frame.getMapper().getServersTable().get(jTable.getSelectedRow() + 1)
						.getHostName());
				this.messagePanel.setMessage(this.frame.getMapper().getServer(jTable.getSelectedRow() + 1)
						.getLastMessageSent());
				if (jTable.getSelectedRowCount() > 1) {
					this.serverName.setText("Multiple");
				}
			}
		}

	}

	public void keyTyped(KeyEvent arg0) {

	}

	/**
	 * This JPanel shows the MessageToServer Object and shows both the
	 * failuresPeriodMean and upTimeMean for the trace for the Server objects
	 * selected.
	 * 
	 * @author Majd Kokaly
	 * 
	 */
	static public class MessageToServerJPanel extends JPanel implements ActionListener, KeyListener,
			PropertyChangeListener, ChangeListener {

		/**
		 * The serialVersionUID is used to universally identify this version of
		 * this class.
		 */
		private static final long serialVersionUID = -8429043770066937928L;

		/**
		 * The array of labels.
		 */
		JLabel[] labels;

		/**
		 * The array of components. (JTextFields, JCheckBox)
		 */
		JComponent[] componenets;

		/**
		 * This array is constructed from N labels (W_1, W_2... W_N) where N is
		 * the N in method 1 in predicting the availability. Please refer to
		 * Section Availability model in the thesis Document.
		 */
		JLabel[] weightsLabels;

		/**
		 * This array of JTextFields to store the values of the weights. Please
		 * refer to Section Availability model in the thesis Document.
		 */
		JTextField[] weightsTF;

		/**
		 * This JButton is used to Apply messages and failuresPeriodMean and
		 * UpTimeMean
		 */
		JButton applyButton = new JButton("Apply");

		/**
		 * This is a layout used to layout components.
		 */
		GridBagConstraints gbConstraints;

		/**
		 * This is the MessageToServer object that this JPanel is view for.
		 */
		MessageToServer message;

	
		/**
		 * The main JPanel containing GUI components
		 */
		JPanel mainPanel = new JPanel();

		/**
		 * This WeightsPanel object is used to view the weight
		 */
		WeightsPanel weighstPanel = new WeightsPanel(4);

		/**
		 * 
		 */
		JPanel buttonsPanel = new JPanel();

		/**
		 * The container of this JPanel
		 */
		ServersAvailabilityJPanel container;

		/**
		 * The default constructor
		 * 
		 * @param container
		 *            is the container of this subject. This used to pass
		 *            messages between the two objects.
		 */
		public MessageToServerJPanel(ServersAvailabilityJPanel container) {
			this.container = container;
			/* ----- Building Main Panel ------ */
			mainPanel.setLayout(new GridBagLayout());

			labels = new JLabel[4];
			labels[0] = new JLabel("Availability");
			labels[1] = new JLabel("Period");
			labels[2] = new JLabel("Availability Mode");
			labels[3] = new JLabel("N");

			componenets = new JComponent[4];
			componenets[0] = new JTextField(10);
			componenets[1] = new JTextField(10);
			componenets[2] = new JComboBox();
			((JComboBox) componenets[2]).addItem(new String("Weighted Average"));
			((JComboBox) componenets[2]).addItem(new String("Recursive"));
			((JComboBox) componenets[2]).addItem(new String("Non Active"));
			((JComboBox) componenets[2]).setSelectedIndex(0);
			((JComboBox) componenets[2]).addActionListener(this);
			componenets[3] = new JTextField(10);
			((JTextField) componenets[3]).addKeyListener(this);
			((JTextField) componenets[3]).addPropertyChangeListener(this);

			gbConstraints = new GridBagConstraints();
			gbConstraints.insets = new Insets(3, 3, 3, 3);
			gbConstraints.fill = GridBagConstraints.WEST;
			gbConstraints.anchor = GridBagConstraints.WEST;
			gbConstraints.gridheight = 1;
			gbConstraints.gridwidth = 1;
			int i;
			for (i = 0; i < labels.length; i++) {
				gbConstraints.gridy = i;

				gbConstraints.gridx = 0;
				mainPanel.add(labels[i], gbConstraints);

				gbConstraints.gridx = 1;
				mainPanel.add(componenets[i], gbConstraints);
			}
			if (((JComboBox) componenets[2]).getSelectedIndex() == 0) {
				labels[3].setText("N");
				if (this.message != null) {
					((JTextField) componenets[3]).setText(message.getN() + "");
				}
			}

			// To force north alignment
			gbConstraints.fill = GridBagConstraints.BOTH;
			gbConstraints.gridy = i;
			mainPanel.add(javax.swing.Box.createVerticalGlue(), gbConstraints);

			/* ----- Building the weights panel ------ */
			this.weighstPanel.refresh(4);

			/* ----- Building the buttons panel ------ */
			buttonsPanel.add(applyButton);
			applyButton.addActionListener(this);

			this.setLayout(new GridBagLayout());
			gbConstraints = new GridBagConstraints();
			gbConstraints.insets = new Insets(3, 3, 3, 3);

			gbConstraints.anchor = GridBagConstraints.PAGE_START;
			gbConstraints.gridheight = 1;
			gbConstraints.gridwidth = 1;
			gbConstraints.gridx = 0;

			gbConstraints.gridy = 0;
			this.add(mainPanel, gbConstraints);

			gbConstraints.gridy = 1;
			this.add(weighstPanel, gbConstraints);

			gbConstraints.gridy = 2;
			this.add(buttonsPanel, gbConstraints);

			gbConstraints.fill = GridBagConstraints.BOTH;
			gbConstraints.gridy = 3;
			gbConstraints.gridx = 0;
			gbConstraints.weighty = 1;
			this.add(javax.swing.Box.createVerticalGlue(), gbConstraints);

		}

		/**
		 * This method is used to hide the weightsPanel when the mode is not
		 * WEIGHTED_AVERAGE
		 */
		public void hideWeights() {
			this.weighstPanel.setVisible(false);
			this.repaint();
		}

		/**
		 * This method is used to show the weightsPanel when the mode is
		 * WEIGHTED_AVERAGE
		 */
		public void showWeights() {
			this.weighstPanel.setVisible(true);
			this.repaint();
		}

		/**
		 * This setter is invoked by the container (the
		 * ServersAvailabilityJPanel) to set a Message object for the JPanel. It
		 * is used when the user select a Server so that this JPanel can view
		 * the appropriate data.
		 * 
		 * @param message
		 *            the message to be set.
		 */
		public void setMessage(MessageToServer message) {
			this.message = message;
			refreshValues();
		}

		/**
		 * This method read the values of the message and modify the data shown
		 * accordingly.
		 */
		public void refreshValues() {
			if (labels == null) {
				return;
			}

			DecimalFormat formatter = new DecimalFormat();
			formatter.setMaximumFractionDigits(4);

			if (this.message != null) {
				((JTextField) componenets[0]).setText(message.getAvailability() + "");
				((JTextField) componenets[1]).setText(message.getForHowLong() + "");
				((JComboBox) componenets[2]).setSelectedIndex(message.getAvailabilityMode());
			}

			if (((JComboBox) componenets[2]).getSelectedIndex() == 1) {
				labels[3].setText("C");
				if (this.message != null) {
					((JTextField) componenets[3]).setText(message.getC() + "");
				}
			}

			if (((JComboBox) componenets[2]).getSelectedIndex() == 0) {
				labels[3].setText("N");
				if (this.message != null) {
					((JTextField) componenets[3]).setText(message.getWeights().length + "");
				}
				if (this.message != null)
					this.weighstPanel.refresh(this.message.getWeights());
			}
		}

		public void clearValues() {
			((JTextField) componenets[0]).setText("");
			((JTextField) componenets[1]).setText("");
			((JTextField) componenets[2]).setText("");
			((JTextField) componenets[3]).setText("");

		}

		public void actionPerformed(ActionEvent e) {
			if (e.getSource() == componenets[2]) {
				if (((JComboBox) componenets[2]).getSelectedIndex() == 1) {
					labels[3].setText("C");
					hideWeights();
					labels[3].setVisible(true);
					componenets[3].setVisible(true);
					((JTextField) componenets[3]).setText(this.message.getC() + "");
					return;
				}
				if (((JComboBox) componenets[2]).getSelectedIndex() == 0) {
					labels[3].setText("N");
					showWeights();
					labels[3].setVisible(true);
					componenets[3].setVisible(true);
					((JTextField) componenets[3]).setText(this.message.getWeights().length + "");
					this.weighstPanel.refresh(this.message.getWeights());
					return;
				}
				// Non-Active Option
				if (((JComboBox) componenets[2]).getSelectedIndex() == 2) {
					labels[3].setText("N");
					hideWeights();
					labels[3].setVisible(false);
					componenets[3].setVisible(false);

					return;
				}

				return;
			}

			if (e.getSource() == applyButton) {

				if (!this.container.isThereASelection()) {
					JOptionPane.showMessageDialog(this.container, "Please select the servers.", "Error",
							JOptionPane.ERROR_MESSAGE);
					return;
				}


				try {
					message.setAvailability(Double.parseDouble(((JTextField) componenets[0]).getText()));
				} catch (NumberFormatException ex) {
					JOptionPane.showMessageDialog(this, "Availability should be a double value.", "Error",
							JOptionPane.ERROR_MESSAGE);
					return;
				}

				try {
					message.setForHowLong(Double.parseDouble(((JTextField) componenets[1]).getText()));
				} catch (NumberFormatException ex) {
					JOptionPane.showMessageDialog(this, "For how long should be a double value.", "Error",
							JOptionPane.ERROR_MESSAGE);
					return;
				}
				message.setAvailabilityMode(((JComboBox) componenets[2]).getSelectedIndex());

				if (message.getAvailabilityMode() == MessageToServer.RECURSIVE_MODE) {
					try {
						message.setC(Double.parseDouble(((JTextField) componenets[3]).getText()));
					} catch (NumberFormatException ex) {
						if (message.getAvailability() != MessageToServer.NON_ACTIVE_MODE) {
							JOptionPane.showMessageDialog(this.container, labels[3].getText().toUpperCase()
									+ " should be a double value.", "Error", JOptionPane.ERROR_MESSAGE);
							return;
						}
					}
				}

				message.setWeights(this.weighstPanel.getWeights());

				if (message.getWeights() == null && message.getAvailabilityMode() == MessageToServer.WEIGHTED_MODE) {
					JOptionPane
							.showMessageDialog(this, "Weights should be numbers", "Error", JOptionPane.ERROR_MESSAGE);
				}

				if (message.getWeights() == null || message.getAvailabilityMode() == MessageToServer.RECURSIVE_MODE
						|| message.getAvailabilityMode() == MessageToServer.NON_ACTIVE_MODE) {
					message.setWeights(new double[1]);
					message.setN(1);
				} else
					message.setN(message.getWeights().length);

				container.applyMessage(message);

			}
		}

		public void keyPressed(KeyEvent e) {

		}

		/**
		 * This method is used to create a new set of text field to contain the
		 * weights when N is changed.
		 */
		public void keyReleased(KeyEvent e) {
			if (e.getSource() == componenets[3]) {
				if (((JComboBox) componenets[2]).getSelectedIndex() == 1) {
					return;
				}
				if (((JComboBox) componenets[2]).getSelectedIndex() == 0) {
					try {
						int n = Integer.parseInt(((JTextField) componenets[3]).getText());
						if (n > 15)
							n = 15;
						this.message.setN(n);
						((JTextField) componenets[3]).setText(this.message.getN() + "");
					} catch (NumberFormatException ex) {
						// ex.printStackTrace();
						return;
					}
					this.weighstPanel.refresh(this.message.getN());
				}
				return;
			}
		}

		public void keyTyped(KeyEvent e) {

		}

		public void stateChanged(ChangeEvent arg0) {

		}

		public void propertyChange(PropertyChangeEvent evt) {

		}
	}

	/**
	 * This class is responsible for viewing the weights.
	 * 
	 * @author Majd Kokaly
	 */
	static public class WeightsPanel extends JPanel {

		/**
		 * 
		 */
		private static final long serialVersionUID = 1943145759520180425L;
		JLabel[] weightsLabel;
		JTextField[] weightsTF;

		/**
		 * Default constructor
		 * 
		 * @param N
		 *            is the number of weights
		 */
		public WeightsPanel(int N) {
			this.setLayout(new GridLayout(N, 2));
			weightsLabel = new JLabel[N];
			weightsTF = new JTextField[N];
			for (int i = 0; i < N; i++) {
				weightsLabel[i] = new JLabel("W_" + (i + 1));
				weightsTF[i] = new JTextField(5);
				this.add(weightsLabel[i]);
				this.add(weightsTF[i]);
			}
		}

		/**
		 * Rebuilds the JPanel using a new value of N
		 * 
		 * @param N
		 *            is the new number of weights
		 */
		public void refresh(int N) {
			this.removeAll();
			this.setLayout(new GridLayout(N, 2));
			weightsLabel = new JLabel[N];
			weightsTF = new JTextField[N];
			for (int i = 0; i < N; i++) {
				weightsLabel[i] = new JLabel("W_" + (i + 1));
				weightsTF[i] = new JTextField(5);
				this.add(weightsLabel[i]);
				this.add(weightsTF[i]);
			}
			this.setVisible(false);
			this.setVisible(true);
			this.repaint();
		}

		/**
		 * Rebuilds the JPanel using a new array of weights
		 * 
		 * @param a
		 *            is the array of the new weights
		 */
		public void refresh(double[] a) {
			if (a == null)
				return;
			this.removeAll();
			this.setLayout(new GridLayout(a.length, 2));
			weightsLabel = new JLabel[a.length];
			weightsTF = new JTextField[a.length];
			for (int i = 0; i < a.length; i++) {
				weightsLabel[i] = new JLabel("W_" + (i + 1));
				weightsTF[i] = new JTextField(5);
				this.add(weightsLabel[i]);
				this.add(weightsTF[i]);
				this.weightsTF[i].setText(a[i] + "");
			}
			this.setVisible(false);
			this.setVisible(true);
			this.repaint();
		}

		/**
		 * This method is used to get the weights entered by the user.
		 * 
		 * @return the weights entered by the user
		 */
		public double[] getWeights() {
			double[] array = new double[weightsTF.length];
			for (int i = 0; i < weightsTF.length; i++) {
				try {
					array[i] = Double.parseDouble(weightsTF[i].getText().trim());
				} catch (NumberFormatException ex) {

					return null;
				}
			}
			return array;
		}
	}

}
