import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Enumeration;

import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

import gnu.io.CommPortIdentifier;

public class SerialPortChooserDialog extends JDialog implements ActionListener, ListSelectionListener {
	private static final long serialVersionUID = 1L;
	
	private boolean onlyOneChoice;
	private boolean emptyChoice;
	private ArrayList<String> portNames;
	private String choosedPort = null;
	
	private JList<String> list;
	private JButton ok;
	private JButton cancel;

	private SerialPortChooserDialog() {
		Enumeration<?> portEnum = CommPortIdentifier.getPortIdentifiers();
		portNames = new ArrayList<>();

		while (portEnum.hasMoreElements()) {
			CommPortIdentifier currPortId = (CommPortIdentifier) portEnum.nextElement();
			portNames.add(currPortId.getName());
		}

		onlyOneChoice = portNames.size() <= 1;
		emptyChoice = portNames.size() == 0;
		if(onlyOneChoice || emptyChoice)
			return;
		
		// JDialog creation
		JPanel mainPanel = new JPanel(new BorderLayout());
		setModal(true);
		setTitle("Serial port chooser");
		
		// title
		mainPanel.add(new JLabel("Choose a serial port : "), BorderLayout.NORTH);
		
		// list ports
		DefaultListModel<String> listModel = new DefaultListModel<>();
		for(String str : portNames)
			listModel.addElement(str);
		list = new JList<>(listModel);
		list.addListSelectionListener(this);
		list.setVisibleRowCount(3);
		list.setLayoutOrientation(JList.VERTICAL);
		list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		
		JScrollPane scrollPane = new JScrollPane(list, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
		scrollPane.setPreferredSize(new Dimension(200, 100));
		mainPanel.add(scrollPane, BorderLayout.CENTER);
		
		// buttons ok / cancel
		JPanel borderLayoutPanel = new JPanel(new BorderLayout());
		JPanel buttonsLayout = new JPanel(new FlowLayout(FlowLayout.LEADING, 5, 3));
		ok = new JButton("Ok");
		cancel = new JButton("Cancel");
		ok.addActionListener(this);
		cancel.addActionListener(this);
		ok.setEnabled(false);
		buttonsLayout.add(cancel);
		buttonsLayout.add(ok);
		borderLayoutPanel.add(buttonsLayout, BorderLayout.EAST);
		mainPanel.add(borderLayoutPanel, BorderLayout.SOUTH);

		// padding
		JPanel padding = new JPanel(new FlowLayout(FlowLayout.LEADING, 5, 5));
		padding.add(mainPanel);
		add(padding);

		setResizable(false);
		pack();
		setLocationRelativeTo(null);
		setVisible(true);
	}
	
	public static String showSerialPortChooserDialog() throws NoSerialPortException {
		SerialPortChooserDialog dialog = new SerialPortChooserDialog();
		if(dialog.emptyChoice)
			throw new NoSerialPortException();
		if(dialog.onlyOneChoice)
			return dialog.portNames.get(0);
		return dialog.choosedPort;
	}

	@Override
	public void actionPerformed(ActionEvent e) {
		if(e.getSource() == ok) {
			choosedPort = list.getSelectedValue();
			dispose();
		} else if(e.getSource() == cancel) {
			dispose();
		}
	}

	@Override
	public void valueChanged(ListSelectionEvent e) {
		if(e.getSource() == list) {
			ok.setEnabled(list.getSelectedIndex() != -1);
		}
	}
}
