package ch.rakudave.jnetmap.view.components;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Frame;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.Vector;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JDialog;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.ListCellRenderer;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import ch.rakudave.jnetmap.controller.Scheduler;
import ch.rakudave.jnetmap.net.NetworkScan;
import ch.rakudave.jnetmap.net.Subnet;
import ch.rakudave.jnetmap.net.status.PingMethod;
import ch.rakudave.jnetmap.util.AlphanumComparator;
import ch.rakudave.jnetmap.util.Icons;
import ch.rakudave.jnetmap.util.Lang;
import ch.rakudave.jnetmap.util.SwingHelper;
import ch.rakudave.jnetmap.util.Tuple;
import ch.rakudave.jnetmap.util.logging.Logger;
@SuppressWarnings("serial")
public class NetworkScanner extends JDialog {
private NetworkScan netScan;
private AlphanumComparator alphaComp = new AlphanumComparator();
public NetworkScanner(final Frame owner, final ch.rakudave.jnetmap.model.Map map) {
super(owner, Lang.getNoHTML("network.scanner"), ModalityType.DOCUMENT_MODAL);
final NetworkScanner _this = this;
setLayout(new BorderLayout(5, 5));
setPreferredSize(new Dimension(500,500));
JPanel main = new JPanel(new BorderLayout(5, 5));
final JList list = new JList();
list.setCellRenderer(new CheckListRenderer());
list.addListSelectionListener(new ListSelectionListener() {
@Override
public void valueChanged(ListSelectionEvent e) {
if (list.getSelectedValue() != null) {
JCheckBox c = ((JCheckBox) list.getSelectedValue());
c.setSelected(!c.isSelected());
}
list.clearSelection();
}
});
final Vector<JCheckBox> checkboxes = new Vector<JCheckBox>();
JPanel topPanel = new JPanel(new BorderLayout());
JPanel topInner = new JPanel(new GridLayout(2, 1, 5, 5));
final JTextField addr = new JTextField(NetworkScan.getLocalAddress());
final JTextField sub = new JTextField();
addr.addFocusListener(new FocusListener() {
@Override public void focusGained(FocusEvent e) {}
@Override
public void focusLost(FocusEvent e) {
if (sub.getText().isEmpty()) autoFill(addr, sub);
}
});
addr.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
autoFill(addr, sub);
}
});
autoFill(addr, sub);
topInner.add(addr);
topInner.add(sub);
final JButton scan = new JButton(Lang.get("port.scan"));
scan.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
try {
if (netScan != null) return;
scan.setEnabled(false);
netScan = new NetworkScan(new Subnet(addr.getText(), sub.getText()), new ChangeListener() {
@Override
@SuppressWarnings("unchecked")
public void stateChanged(ChangeEvent e) {
InetAddress address = ((Tuple<InetAddress, PingMethod>)e.getSource()).getFirst();
JCheckBox c = new JCheckBox(address.getHostAddress(), true);
checkboxes.add(c);
if (NetworkScan.tryFindIP(map, address) != null) {
c.setEnabled(false);
c.setSelected(false);
}
Collections.sort(checkboxes, new Comparator<JCheckBox>() {
@Override
public int compare(JCheckBox o1, JCheckBox o2) {
return alphaComp.compare(o1.getText(), o2.getText());
}
});
list.setListData(checkboxes);
}
});
Scheduler.execute(new Runnable() {
@Override
public void run() {
netScan.start(true);
}
});
Scheduler.execute(new Runnable() {
@Override
public void run() {
scan.setIcon(Icons.get("busy"));
scan.setText("");
while (!netScan.isDone()) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
Logger.debug("Interrupted", e);
}
}
scan.setIcon(null);
scan.setText(Lang.get("action.done"));
}
});
} catch (Exception ex) {
Logger.error("Unable to conduct NetScan", ex);
}
}});
topPanel.add(topInner, BorderLayout.CENTER);
topPanel.add(scan, BorderLayout.EAST);
main.add(topPanel, BorderLayout.NORTH);
main.add(new JScrollPane(list));
JPanel bottomRow = new JPanel(new FlowLayout(FlowLayout.TRAILING, 5, 5));
JButton cancel = new JButton(Lang.get("action.cancel"), Icons.get("cancel"));
cancel.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (netScan != null) netScan.cancel();
_this.dispose();
}
});
final JButton ok = new JButton(Lang.get("action.add"), Icons.get("add"));
ok.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (netScan != null) {
ok.setEnabled(false);
if (!netScan.isDone()) netScan.cancel();
Map<InetAddress, PingMethod> hosts = new HashMap<InetAddress, PingMethod>(netScan.getFoundHosts());
for (JCheckBox c : checkboxes) {
if (!c.isSelected()) {
try {
hosts.remove(InetAddress.getByName(c.getText()));
} catch (UnknownHostException ex) {
Logger.warn("Failed to remove INetAddress ", ex);
}
}
}
Logger.debug("Adding to Map: " + Arrays.toString(hosts.keySet().toArray()));
netScan.addToMap(hosts, map);
_this.dispose();
}
}
});
bottomRow.add(cancel);
bottomRow.add(ok);
add(main, BorderLayout.CENTER);
add(bottomRow, BorderLayout.SOUTH);
pack();
SwingHelper.centerTo(owner, this);
setVisible(true);
}
private void autoFill(JTextField address, JTextField subnet) {
try {
Subnet s = new Subnet((address.getText().contains("/"))?address.getText():address.getText()+"/24");
address.setText(s.getInfo().getLowAddress());
subnet.setText(s.getInfo().getNetmask());
} catch (Exception e) {
Logger.warn("Unable to autoFill address "+address.getText(), e);
}
}
private class CheckListRenderer implements ListCellRenderer {
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean hasFocus) {
return (Component) value;
}
}
}