package scheduler;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.LayoutManager;
import java.awt.TextField;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTable;
import javax.swing.border.Border;
import javax.swing.table.DefaultTableCellRenderer;

import common.Direction;


public class SystemGUI {

	private JPanel[] elevatorPanel;
	private int numberOfFloors;
	private Map<Integer,TextField> elevatorStatus = new HashMap<>();
	private Map<Integer,TextField> elevatorDestUp = new HashMap<>();
	private Map<Integer,TextField> elevatorDestDown = new HashMap<>();

	private Map<Integer,JTable> elevatorTables = new HashMap<>();
	
	private static SystemGUI instance;
	
	public static SystemGUI createSystemGUI(int numberOfElevators, int numberOfFloors, boolean showGUI) {
		instance = new SystemGUI(numberOfElevators, numberOfFloors, showGUI);
		return instance;
	}
	
	/**
	 * Assumes createSystemGUI has already been called
	 * @return
	 */
	public static SystemGUI getInstance() {
		return instance;
	}

	/**
	 * SystemGUI will create a GUI for elevator simulator
	 * that sits on top of scheduler subsystem
	 * @param numberOfElevators number of elevators for the system (start from 1)
	 * @param numberOfFloors number of floors for system (start from 1)
	 */
	private SystemGUI(int numberOfElevators, int numberOfFloors, boolean showGUI) {
		this.numberOfFloors = numberOfFloors;
		elevatorPanel = new JPanel [numberOfElevators];
		JFrame frame = new JFrame("Elevator");
		JPanel outterPanel = new JPanel();
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		outterPanel.setPreferredSize(new Dimension(1200,750));
		frame.add(outterPanel);
		frame.pack();
		for (int i = 0; i < numberOfElevators; i++) {
			elevatorPanel[i] = createElevatorPanel(i+1);
			outterPanel.add(elevatorPanel[i]);
		}

		// updateElevatorLocation(2, 2);
		//  updateElevatorStatus(2, "haha");
		//  ArrayList<Integer> temp = new ArrayList<Integer>();
		//  temp.add(5);
		//  temp.add(6);
		//  updateElevatorDestUp(2, temp);
		if (showGUI) {
			frame.setVisible(true);
		}
	}

	private JPanel createElevatorPanel(int numberOfELevator) {
		Border blackline = BorderFactory.createLineBorder(Color.black);

		JPanel outterPanel = new JPanel();
		JPanel upperPanel = new JPanel();
		JPanel lowerPanel = new JPanel();
		JPanel whiteSpace = new JPanel(); // seperation between upper and lower panel

		whiteSpace.setPreferredSize(new Dimension(200,20));
		outterPanel.setPreferredSize(new Dimension(250,700));
		outterPanel.setLayout((LayoutManager) new BoxLayout(outterPanel, BoxLayout.PAGE_AXIS));

		upperPanel.setPreferredSize(new Dimension(150,200));
		lowerPanel.setPreferredSize(new Dimension(150,750));
		upperPanel.setBorder(blackline);
		lowerPanel.setBorder(blackline);

		//Upper Panel
		upperPanel.add(createElevatorStatus(numberOfELevator));

		//Lower Panel
		JPanel tableHeader = new JPanel();
		tableHeader.setLayout(new FlowLayout(FlowLayout.LEFT));
		tableHeader.setPreferredSize(new Dimension(150,20));
		JLabel firstColumnHeader = new JLabel("FLOOR");
		firstColumnHeader.setPreferredSize(new Dimension(70,20));
		tableHeader.add(firstColumnHeader);
		tableHeader.add(new JLabel("LOCATION"));
		lowerPanel.add(tableHeader);
		lowerPanel.add(createElevatorTable(numberOfELevator));

		outterPanel.add(upperPanel);
		outterPanel.add(whiteSpace);
		outterPanel.add(lowerPanel);
		return outterPanel;
	}

	private JPanel createElevatorStatus(int numberOfELevator) {
		JPanel panel = new JPanel();
		JPanel upper = new JPanel();
		JPanel lower = new JPanel();
		panel.setLayout((LayoutManager) new BoxLayout(panel, BoxLayout.PAGE_AXIS));
		lower.setLayout((LayoutManager) new BoxLayout(lower, BoxLayout.PAGE_AXIS));

		//Elevator status
		TextField elevatorStatusTF = new TextField();
		elevatorStatusTF.setPreferredSize(new Dimension(150,20));
		elevatorStatusTF.setEditable(false);
		elevatorStatus.put(numberOfELevator, elevatorStatusTF);
		upper.add(new JLabel("Status : "));
		upper.add(elevatorStatusTF);

		//Elevator destination list
		TextField elevatorDestUpTF = new TextField();
		TextField elevatorDestDownTF = new TextField();
		elevatorDestUpTF.setEditable(false);
		elevatorDestDownTF.setEditable(false);
		elevatorDestUp.put(numberOfELevator, elevatorDestUpTF);
		elevatorDestDown.put(numberOfELevator, elevatorDestDownTF);
		lower.add(new JLabel("Destinations : "));
		lower.add(new JLabel("UP : "));
		lower.add(elevatorDestUpTF);
		lower.add(new JLabel("DOWN : "));
		lower.add(elevatorDestDownTF);

		panel.add(new JLabel("Elevator" + numberOfELevator));
		panel.add(upper);
		panel.add(lower);
		return panel;
	}

	private JTable createElevatorTable(int numberOfELevator) {
		String[] columnNames = {"FLOOR", "LOCATION"};
		Object[][] data = new Object[numberOfFloors][2];
		//create table that highest number at the top, lowest number at bottom
		for (int i = 0; i < numberOfFloors; i++) {
			data[i][0] = numberOfFloors-i;
			data[i][1] = new String(" ");
		}

		data[numberOfFloors - 1][1] = "<html><b>X</b></html>"; //mark X on first floor
		JTable table = new JTable(data, columnNames);
		table.setEnabled(false);

		//styling
		DefaultTableCellRenderer centerRenderer = new DefaultTableCellRenderer();
		centerRenderer.setHorizontalAlignment( JLabel.CENTER );
		table.getColumnModel().getColumn(0).setCellRenderer( centerRenderer );
		table.getColumnModel().getColumn(1).setCellRenderer( centerRenderer );
		table.getColumnModel().getColumn(0).setPreferredWidth(70);
		table.getColumnModel().getColumn(1).setPreferredWidth(150);
		table.setBackground(Color.lightGray);

		elevatorTables.put(numberOfELevator, table);
		return table;
	}

	/**
	 * updateElevator updates elevator location on the table
	 * @param elevatorId (start from 1)
	 * @param newFloor (start from 1)
	 */
	public void updateElevatorLocation(int elevatorId, int newFloor) {
		clearElevatorColumn(elevatorId);
		elevatorTables.get(elevatorId).setValueAt("<html><b>X</b></html>", numberOfFloors - newFloor, 1);
	}
	
	/**
	 * updateElevator updates elevator location on the table
	 * @param elevatorId (start from 1)
	 * @param newFloor (start from 1)
	 */
	public void updateElevatorLocationAfterError(int elevatorId, int newFloor) {
		clearElevatorColumn(elevatorId);
		elevatorTables.get(elevatorId).setValueAt("<html><b><font color=red>X</font></b></html>", numberOfFloors - newFloor, 1);
	}

	/**
	 * updateElevatorStatus updates elevator status
	 * @param elevatorId (start from 1)
	 * @param status
	 */
	public void updateElevatorStatus(int elevatorId, String status) {
		elevatorStatus.get(elevatorId).setText(status);
	}

	/**
	 * updateElevatorDestUp updates the list of UP destinations,
	 * have to pass in the new destination list
	 * @param elevatorId (start from 1)
	 * @param floors
	 */
	public void updateElevatorDestUp(int elevatorId, Set<Integer> floors) {
		elevatorDestUp.get(elevatorId).setText(floors.toString());
	}

	/**
	 * updateElevatorDestUp updates the list of UP destinations,
	 * have to pass in the new destination list
	 * @param elevatorId (start from 1)
	 * @param floors
	 */
	public void updateElevatorDestDown(int elevatorId, Set<Integer> floors) {
		elevatorDestDown.get(elevatorId).setText(floors.toString());
	}

	public void updateDestinationFloors(int elevatorId, Map<Direction, TreeMap<Integer, Boolean>> destinationFloors) {
		updateElevatorDestUp(elevatorId, destinationFloors.get(Direction.UP).keySet());
		updateElevatorDestDown(elevatorId, destinationFloors.get(Direction.DOWN).keySet());
	}

	private void clearElevatorColumn(int elevatorId) {
		JTable table = elevatorTables.get(elevatorId);
		for (int i = 0; i < table.getRowCount(); i++) {
			table.setValueAt("", i, 1);
		}
	}
}
