package interfacing;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;

import javax.swing.*;

import mapping.data.JobClassesTable;


/**
 * This class with the class JobClassesTableModelListener are
 * the view and controller of the Job Classes of the Mapper object. 
 * They simply view the Job Classes and allow user to insert new classes.
 */
public class JobClassesTableJPanel extends JPanel implements PropertyChangeListener, ActionListener {
	
	/**
	 * 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" , "Execution Time" , "Arrival Rate" };
	

	/**
	 * The MainFrame object containing this
	 */
	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 JobClassesTableModelListener jobClassesTableModelListener;
	
	/** 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 righScrollPane;
	
	/** The panel that holds the jTable and its scroll pane*/
	private JPanel jTableContainer;
	
	/** The add button. Used to add new Job Classes.*/
	private JButton addButton;
	
	/** The remove button. Used to remove  Job Classes.*/
	private JButton removeButton;
	
	/** The panel that holds the add and remove buttons.*/
	private JPanel buttonsConatainers;
	
	/** The panel used to insert info about a new Job Class object.*/
	private PropertiesJPanel propPanel;
	
	/** This button used to submit the information inserted in proPanel.*/
	private JButton submitButton;
	
	/** Just a container for both propPanel and submitButton.*/
	private JPanel propPanelContainer;
	
	/**A panel which contains the File name*/
	private JPanel filelocale;
	
	/**The label which contains the file name*/
	private JLabel filename;
	
	public JobClassesTable getJobClassesTable() {
		return this.frame.getMapper().getClassesTable();
	}

	

	/**
	 * The default constructor. It initializes and lays the GUI objects.
	 * 
	 */
	public JobClassesTableJPanel(final MainFrame frame) {
		// Setting the job classes table
		this.frame = frame;
		
		// Initialize the GUI components
		filename = new JLabel("The file was loaded from: " + frame.getReadFile());
		leftScrollPane = new JScrollPane(); // left side of of splitPane
		righScrollPane = 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());
		splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, leftScrollPane, righScrollPane);
		splitPane.setDividerLocation(400);
		filelocale = new JPanel();
		filelocale.add(filename);
		
		// Registering the Listener which responsible for validating data and send it the view
		jobClassesTableModelListener = new JobClassesTableModelListener(getJobClassesTable());
		
		
		/* Building jTableContainer*/
			jTableContainer.setLayout(new GridBagLayout());
			GridBagConstraints gbConstraints = new GridBagConstraints();
			gbConstraints.gridx = 0;
			gbConstraints.gridy = 0;
			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 = 1;
			//Building a panel containing + and - buttons
			buttonsConatainers = new JPanel();
			addButton = new JButton("");
			addButton.setIcon(new ImageIcon(MainFrame.iconsFolder + "/" + "edit_add_22.png"));
			addButton.addActionListener(this);
			removeButton = new JButton("");
			removeButton.setIcon(new ImageIcon(MainFrame.iconsFolder + "/" + "edit_remove_22.png"));
			removeButton.addActionListener(this);
			buttonsConatainers.add(addButton);
			buttonsConatainers.add(removeButton);
			jTableContainer.add( buttonsConatainers , gbConstraints ); // add buttons panel and its pane to jTableContainer
			
			gbConstraints.gridy=2;
			
			jTableContainer.add(filelocale, gbConstraints);
			// This segment forces the north alignment of the components
			gbConstraints.weighty=1.0;
			gbConstraints.fill=GridBagConstraints.BOTH;
			gbConstraints.gridy=3;
			jTableContainer.add(javax.swing.Box.createVerticalGlue(), gbConstraints);
			
		this.leftScrollPane.setViewportView(jTableContainer);
		this.leftScrollPane.setAlignmentY(JScrollPane.TOP_ALIGNMENT);
		this.add(splitPane);
		jTable.setGridColor(Color.BLACK);	
		
		this.buildPropretyJPanel();
		this.hidePropertyJPanel();
		
		this.fillJTable();
		int h = ( 1 + jTable.getModel().getRowCount() ) * jTable.getRowHeight() + 100;
		this.setPreferredSize(new Dimension(500, h));
		splitPane.addPropertyChangeListener(this);	
	}
	
	
	/** This method fills the table model (tableModel) of the corresponding data 
	 * from the jobClassesTable object that this JPanel is the view for.
	 * The jTable object is changed correspondingly.
	 */
	public void fillJTable() {
		tableModel = new OurDefaultTableModel(columnNames, 0);
		jTable.setModel(tableModel);
		for (int i = 0; i < this.getJobClassesTable().size(); i++) {
			String[] s =  {this.getJobClassesTable().get(i+1).getIndex() +"" , this.getJobClassesTable().get(i+1).getexecutionTime() +"", this.getJobClassesTable().get(i+1).getArrivalRate()+""};
			tableModel.addRow(s);
		}
		jobClassesTableModelListener = new JobClassesTableModelListener(this.getJobClassesTable());
		tableModel.addTableModelListener(jobClassesTableModelListener);
		
		
	}
	
	public void printClasses() {
		this.getJobClassesTable().printAll();
	}
	
	
	/** 
	 * This method build the property table
	 */
	public void buildPropretyJPanel() {
		// Properties of JobClass
		String[] names = { "Execution Time" , "Arrival Rate"};
		// Creating a property JPanel
		propPanel = new PropertiesJPanel(names, null);
		submitButton = new JButton("Submit");
		submitButton.addActionListener(this);
		propPanelContainer = new JPanel();
		propPanelContainer.setLayout(new GridBagLayout());
		GridBagConstraints gbConstraints = new GridBagConstraints();
		gbConstraints.anchor = GridBagConstraints.CENTER;
		gbConstraints.gridx = 0;
		gbConstraints.gridy =0;
		propPanelContainer.add( propPanel , gbConstraints );
		gbConstraints.gridx = 0;
		gbConstraints.gridy =1;
		propPanelContainer.add(submitButton, gbConstraints );
		

		// This segment forces the north alignment of the components
		gbConstraints.weighty=1.0;
		gbConstraints.fill=GridBagConstraints.BOTH;
		gbConstraints.gridy=2;
		propPanelContainer.add(javax.swing.Box.createVerticalGlue(),gbConstraints);
		
		gbConstraints.gridheight = 3;
		gbConstraints.weightx=0.0;
		gbConstraints.weightx=1.0;
		gbConstraints.gridx = 1;
		gbConstraints.gridy =0;
		propPanelContainer.add(javax.swing.Box.createHorizontalGlue(),gbConstraints);
		
		this.righScrollPane.setViewportView(propPanelContainer);
		this.righScrollPane.setAlignmentY(JScrollPane.TOP_ALIGNMENT);
		
		this.repaint();
	}
	
	/**
	 * This method shows the JPanel which the user can use to enter info about the job class.
	 */
	public void showPropertyJPanel() {
		this.propPanel.clearFields();
		this.propPanelContainer.setVisible(true);
	}
	
	public void hidePropertyJPanel() {
		this.propPanelContainer.setVisible(false);
	}
	
	/**
	 * This method removes a Job Class when removeButton is clicked
	 */
	public void removeClass() {
		if ( jTable.getSelectedRow() < 0 ) { // Not selected 
			JOptionPane.showMessageDialog( this , "Please select a job class from the table." , "Error", JOptionPane.ERROR_MESSAGE);
			return;
		}
		this.getJobClassesTable().removeJobClass( jTable.getSelectedRow() + 1 );
		this.fillJTable();
		reSizeJTable();
	}
	
	/**
	 * This method resizes the JTable
	 */
	private void reSizeJTable() {
		if (jTable == null)
			return;
		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);
		this.setPreferredSize(  new Dimension ( 500 , d.height + 70) );
	}
	
	public void repaint() {
		
		reSizeJTable();
		super.repaint();
	}

	/**
	 * This handler handles 3 events: 1) adding a Job Class 2) removing a Job Class 3) Submitting a new class
	 */
	public void actionPerformed(ActionEvent e) {
		if (e.getSource() == addButton) {
			showPropertyJPanel();
		}
		if (e.getSource() == removeButton) {
			removeClass();
		}
		if (e.getSource() == submitButton) {
			try {
				this.getJobClassesTable().addJobClass(  Double.parseDouble(propPanel.getValue(1))  , Long.parseLong(propPanel.getValue(0)) );
			} catch (NumberFormatException ex) {
				JOptionPane.showMessageDialog( this , "Please enter valid numbers." , "Error", JOptionPane.ERROR_MESSAGE);
				return;
			}
			this.fillJTable();
			hidePropertyJPanel();
			this.splitPane.setDividerLocation(this.splitPane.getDividerLocation()+1);
		}
	}
	
	/**
	 * This handler is triggered when the divider location of the splitPane is changed.
	 */
	public void propertyChange(PropertyChangeEvent evt) {
		reSizeJTable();
	}
	
	/**
	 * This method disables input from user
	 */
	public void disableInput() {
		tableModel.setEditable(false);
		this.addButton.setEnabled(false);
		this.removeButton.setEnabled(false);
	}
	
	/**
	 * This method enable input from user
	 */
	public void enableInput() {
		tableModel.setEditable(true);
		this.addButton.setEnabled(true);
		this.removeButton.setEnabled(true);
	}
	
	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();
		}
	}	
}

