package me.legrange.panstamp.gui.model; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.LinkedList; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.event.TableModelEvent; import javax.swing.event.TableModelListener; import javax.swing.table.TableModel; import me.legrange.panstamp.Endpoint; import me.legrange.panstamp.EndpointListener; import me.legrange.panstamp.Network; import me.legrange.panstamp.NetworkException; import me.legrange.panstamp.NetworkListener; import me.legrange.panstamp.PanStamp; import me.legrange.panstamp.PanStampListener; import me.legrange.panstamp.Register; import me.legrange.panstamp.RegisterListener; import me.legrange.panstamp.event.AbstractEndpointListener; import me.legrange.panstamp.event.AbstractNetworkListener; import me.legrange.panstamp.event.AbstractPanStampListener; import me.legrange.panstamp.event.AbstractRegisterListener; /** * * @author gideon */ class EndpointTableModel implements TableModel { @Override public int getRowCount() { synchronized (data) { return data.size(); } } @Override public int getColumnCount() { return 2; } @Override public String getColumnName(int columnIndex) { return columnNames[columnIndex]; } @Override public Class<?> getColumnClass(int columnIndex) { return columnClasses[columnIndex]; } @Override public boolean isCellEditable(int rowIndex, int columnIndex) { return false; } @Override public Object getValueAt(int rowIndex, int columnIndex) { Entry entry; synchronized (data) { if (rowIndex < data.size()) { entry = data.get(rowIndex); } else { return null; } } switch (columnIndex) { case 0: return timeFormat.format(new Date(entry.timestamp)); case 1: return entry.message; } return null; } @Override public void setValueAt(Object aValue, int rowIndex, int columnIndex) { } @Override public void addTableModelListener(TableModelListener l) { listeners.add(l); } @Override public void removeTableModelListener(TableModelListener l) { listeners.remove(l); } static EndpointTableModel create() { return new EndpointTableModel(); } void addGateway(Network gw) { gw.addListener(gatewayL); for (PanStamp ps : gw.getDevices()) { add(ps); } } void removeGateway(Network gw) throws NetworkException { gw.removeListener(gatewayL); for (PanStamp ps : gw.getDevices()) { remove(ps); } } void add(String msg) { long timeStamp = System.currentTimeMillis(); synchronized (data) { data.add(0, new Entry(timeStamp, msg)); if (data.size() > 1000) { for (int i = 0; i < 100; ++i) { data.remove(data.size() - 1); } } } for (TableModelListener l : listeners) { l.tableChanged(new TableModelEvent(this, 0, 0, -1, TableModelEvent.INSERT)); } } EndpointTableModel() { this.listeners = new LinkedList<>(); } private String productCodeMessage(PanStamp ps) throws NetworkException { return String.format("Device %d identified as %s/%s", ps.getAddress(), ps.getManufacturerId(), ps.getProductId()); } private String syncStateMessage(PanStamp ps, int state) throws NetworkException { String mode; switch (state) { case 0: mode = "Restarting"; break; case 1: mode = "Wireless reception enabled"; break; case 2: mode = "Wireless reception disabled"; break; case 3: mode = "Synchronization mode, wireless reception enabled"; break; case 4: mode = "Low battery state"; break; default: mode = "" + state; } return String.format("Device %d reported state: %s", ps.getAddress(), mode); } private String formatValue(Endpoint ep) throws NetworkException { return Format.formatValue(ep); } private void add(PanStamp ps) { if (ps.getNetwork().isOpen()) { add(String.format("Detected new device with address %d", ps.getAddress())); } ps.addListener(panStampL); for (Register reg : ps.getRegisters()) { add(reg); } } private void remove(PanStamp ps) throws NetworkException { ps.removeListener(panStampL); for (Register reg : ps.getRegisters()) { remove(reg); } } private void add(Register reg) { if (reg.getDevice().getNetwork().isOpen()) { add(String.format("Learnt of register %d for device %d", reg.getId(), reg.getDevice().getAddress())); } reg.addListener(registerL); for (Endpoint ep : reg.getEndpoints()) { add(ep); } } private void remove(Register reg) throws NetworkException { reg.removeListener(registerL); for (Endpoint ep : reg.getEndpoints()) { remove(ep); } } private void add(Endpoint ep) { if (ep.getRegister().getDevice().getNetwork().isOpen()) { add(String.format("Learnt of endpoint '%s' for register %d on device %d", ep.getName(), ep.getRegister().getId(), ep.getRegister().getDevice().getAddress())); } ep.addListener(endpointL); } private void remove(Endpoint ep) { ep.removeListener(endpointL); } private static class Entry { public Entry(long timestamp, String message) { this.timestamp = timestamp; this.message = message; } private long timestamp; private String message; } private final List<Entry> data = new ArrayList<>(); private final List<TableModelListener> listeners; private final DateFormat timeFormat = new SimpleDateFormat("HH:mm:ss.SSS"); private static final String columnNames[] = {"Timestamp", "Event"}; private static final Class columnClasses[] = {String.class, String.class}; // GatewayListener, PanStampListener, RegisterListener, EndpointListener private final NetworkListener gatewayL = new AbstractNetworkListener() { @Override public void deviceDetected(Network gw, PanStamp dev) { add(dev); } }; private final PanStampListener panStampL = new AbstractPanStampListener() { @Override public void registerDetected(PanStamp dev, Register reg) { add(reg); } @Override public void syncStateChange(PanStamp dev, int syncState) { try { add(syncStateMessage(dev, syncState)); } catch (NetworkException ex) { Logger.getLogger(EndpointTableModel.class.getName()).log(Level.SEVERE, null, ex); } } @Override public void productCodeChange(PanStamp dev, int manufacturerId, int productId) { try { add(productCodeMessage(dev)); } catch (NetworkException ex) { Logger.getLogger(EndpointTableModel.class.getName()).log(Level.SEVERE, null, ex); } } }; private final RegisterListener registerL = new AbstractRegisterListener() { @Override public void endpointAdded(Register reg, Endpoint ep) { add(ep); } }; private final EndpointListener endpointL = new AbstractEndpointListener() { @Override public void valueReceived(Endpoint ep, Object value) { try { if (ep.getRegister().getDevice().getNetwork().isOpen()) { add(String.format("%s in address %d on node %d changed to %s", ep.getName(), ep.getRegister().getId(), ep.getRegister().getDevice().getAddress(), formatValue(ep))); } } catch (NetworkException ex) { Logger.getLogger(EndpointTableModel.class.getName()).log(Level.SEVERE, null, ex); } } }; }