001package jmri.jmrix.can.cbus.swing.nodeconfig;
002
003import java.awt.BorderLayout;
004import java.awt.Desktop;
005import java.awt.event.ActionEvent;
006import java.beans.PropertyChangeEvent;
007import java.io.IOException;
008import java.net.URI;
009import java.net.URISyntaxException;
010import javax.swing.JButton;
011import javax.swing.JLabel;
012import javax.swing.JPanel;
013import javax.swing.JScrollPane;
014import javax.swing.JTextArea;
015import jmri.jmrix.can.cbus.node.CbusNode;
016import jmri.jmrix.can.cbus.node.CbusNodeConstants;
017import jmri.jmrix.can.cbus.node.CbusNodeParameterManager;
018
019import org.slf4j.Logger;
020import org.slf4j.LoggerFactory;
021
022/**
023 *
024 * @author Steve Young Copyright (C) 2018
025 */
026public class CbusNodeInfoPane extends CbusNodeConfigTab {
027
028    private JButton nodesupportlinkbutton;
029    private URI supportlink;
030    private JLabel header;
031    private JPanel menuPane;
032    protected JTextArea textArea;
033    private CbusNodeParameterManager paramMgr;
034    private JScrollPane textAreaPanel;
035
036    private JPanel paneToDisplay;
037
038    /**
039     * Create a new instance of CbusNodeInfoPane.
040     * @param main the NodeConfigToolPane this is a component of
041     */
042    public CbusNodeInfoPane(NodeConfigToolPane main) {
043        super(main);
044    }
045
046    /**
047     * {@inheritDoc}
048     */
049    @Override
050    public void propertyChange(PropertyChangeEvent ev){
051        jmri.util.ThreadingUtil.runOnGUIEventually( ()->{
052            paramsHaveUpdated();
053        });
054    }
055
056    /**
057     * {@inheritDoc}
058     */
059    @Override
060    public String getTitle(){
061        return Bundle.getMessage("NodeInfo");
062    }
063
064    /**
065     * Initialise the pane for a particular CbusNode ( or CbusBackupNode )
066     * @param node the node to display info for
067     */
068    @Override
069    public void changedNode(CbusNode node) {
070        if (paneToDisplay==null) {
071            paneToDisplay = newInfoPane();
072            add(paneToDisplay);
073        }
074        paramMgr = node.getNodeParamManager();
075        paramsHaveUpdated();
076        validate();
077        repaint();
078
079    }
080
081    private JPanel newInfoPane(){
082
083        JPanel newPane = new JPanel();
084        newPane.setLayout(new BorderLayout() );
085
086        nodesupportlinkbutton = new JButton("");
087        nodesupportlinkbutton.addActionListener((ActionEvent e) -> {
088            openUri(supportlink);
089        });
090
091        textArea = new JTextArea();
092        textArea.setEditable(false);
093        textArea.setMargin( new java.awt.Insets(10,10,10,10) );
094        textAreaPanel = new JScrollPane(textArea);
095
096        header = new JLabel("");
097        menuPane = new JPanel();
098        menuPane.add(header);
099        menuPane.add(nodesupportlinkbutton);
100
101        newPane.add(menuPane, BorderLayout.PAGE_START);
102        newPane.add(textAreaPanel, BorderLayout.CENTER);
103        newPane.validate();
104        newPane.repaint();
105
106        return newPane;
107    }
108
109    private void appendIfKnown( StringBuilder sb, int paramToCheck, String label ){
110
111        // log.info("returning param index {} val {}",paramToCheck,paramMgr.getParameter(paramToCheck));
112
113        if (paramMgr.getParameter(paramToCheck) > -1) {
114                appendRaw(sb,String.valueOf(paramMgr.getParameter(paramToCheck)),label);
115        }
116    }
117
118    private void appendRaw( StringBuilder sb, Object value, String label ){
119        sb.append (label).append (" : ").append (value).append(System.getProperty("line.separator"));
120    }
121
122    private void setHeaderText() {
123        StringBuilder buildheader = new StringBuilder();
124        buildheader.append("<html><h3>");
125        buildheader.append(CbusNodeConstants.getManu(paramMgr.getParameter(1)));
126        buildheader.append(" ");
127        buildheader.append(nodeOfInterest.getNodeStats().getNodeTypeName());
128        buildheader.append("</h3></html>");
129        header.setText(buildheader.toString());
130    }
131
132    /**
133     * Recalculates pane following notification from CbusNode that parameters have changed
134     */
135    private void paramsHaveUpdated() {
136
137        updateSupportButton();
138
139        setHeaderText();
140
141        StringBuilder textAreaString = new StringBuilder();
142
143        appendRaw(textAreaString,nodeOfInterest.getNodeNumber(),Bundle.getMessage("NodeNumberTitle"));
144
145        appendNodeTypeInfo(textAreaString);
146
147        appendIfKnown(textAreaString, 6, Bundle.getMessage("NodeVariables"));
148
149        appendIfKnown(textAreaString, 0, "Parameters");
150
151        if ( nodeOfInterest.getNodeEventManager().getTotalNodeEvents()> -1 ) {
152            appendRaw(textAreaString,nodeOfInterest.getNodeEventManager()
153                .getTotalNodeEvents(), "Current Events");
154        }
155
156        appendIfKnown(textAreaString, 4, "Max Events");
157        appendIfKnown(textAreaString, 5, "Max Event Variables per Event");
158
159        if ((paramMgr.getParameter(0)>9) && (paramMgr.getParameter(10)>0)) {
160            textAreaString.append (CbusNodeConstants.getBusType(paramMgr.getParameter(10)));
161            textAreaString.append (" ");
162            textAreaString.append (Bundle.getMessage("BusType"));
163            textAreaString.append(System.getProperty("line.separator"));
164        }
165
166        appendRaw(textAreaString, Math.max(0,nodeOfInterest.getNodeStats()
167            .totalNodeBytes()), "Current Node Data Bytes");
168
169        addBackupInfo(textAreaString);
170
171        appendRaw(textAreaString, nodeOfInterest.getsendsWRACKonNVSET(), "Sends WRACK Following NV Set");
172
173        appendAllParams(textAreaString);
174
175        //   nodePartTwobuilder.append ("<p> Is Bootable Y / N</p>");
176        //   nodePartTwobuilder.append ("<p> Processor : </p>");
177        //   nodePartTwobuilder.append ("<p> Flags </p>");
178
179        if ( !(textArea.getText().equals(textAreaString.toString()) )) {
180            textArea.setText(textAreaString.toString());
181            textArea.setCaretPosition(0);
182        }
183    }
184
185    private void appendNodeTypeInfo(StringBuilder sb) {
186
187        if (paramMgr.getParameter(1) > -1 &&
188            paramMgr.getParameter(3) > -1 ) {
189
190            sb.append(Bundle.getMessage("ManufacturerType",
191                paramMgr.getParameter(1),
192                CbusNodeConstants.getManu(paramMgr.getParameter(1)),
193                paramMgr.getParameter(3)));
194
195            sb.append(System.getProperty("line.separator"));
196
197        }
198
199        if (!nodeOfInterest.getNodeStats().getNodeTypeName().isEmpty()){
200            sb.append(Bundle.getMessage("IdentifiesAs",
201                nodeOfInterest.getNodeStats().getNodeTypeName(),
202                CbusNodeConstants.getModuleTypeExtra(
203                    paramMgr.getParameter(1),
204                    paramMgr.getParameter(3)))
205            );
206            sb.append(System.getProperty("line.separator"));
207        }
208
209        appendFirmware(sb);
210
211    }
212
213    private void appendFirmware(StringBuilder sb) {
214
215        if ((paramMgr.getParameter(2)>0) &&
216            (paramMgr.getParameter(7)>0)) {
217            sb.append (Bundle.getMessage("FirmwareVer",
218                paramMgr.getParameter(7),
219                Character.toString((char) paramMgr.getParameter(2))));
220
221            if ((paramMgr.getParameter(0)>19) && (paramMgr.getParameter(20)>0) ){
222                sb.append (Bundle.getMessage("FWBeta"));
223                sb.append (paramMgr.getParameter(20));
224            }
225            sb.append(System.getProperty("line.separator"));
226        }
227    }
228
229
230    private void addBackupInfo(StringBuilder sb) {
231
232        sb.append(System.getProperty("line.separator"));
233
234        appendRaw(sb, nodeOfInterest.getNodeBackupManager()
235            .getBackups().size(), "Entries in Node xml file");
236
237        appendRaw(sb, nodeOfInterest.getNodeBackupManager()
238            .getNumCompleteBackups(), "Num Backups in Node xml file");
239
240        if( nodeOfInterest.getNodeBackupManager().getNumCompleteBackups()>0 ) {
241        appendRaw(sb, nodeOfInterest.getNodeBackupManager().getFirstBackupTime(), "First entry");
242        appendRaw(sb, nodeOfInterest.getNodeBackupManager().getLastBackupTime(), "Last entry");
243        }
244    }
245
246    private void appendAllParams(StringBuilder sb) {
247
248        if (!paramMgr.getParameterHexString().isEmpty()) {
249            sb.append(System.getProperty("line.separator"));
250            sb.append ("Parameter Hex String : ");
251            sb.append (paramMgr.getParameterHexString());
252            sb.append(System.getProperty("line.separator"));
253        }
254
255
256        sb.append(System.getProperty("line.separator"));
257        for (int i = 1; i <= paramMgr.getParameter(0); i++) {
258            if ( paramMgr.getParameter(i) > -1 ) {
259                sb.append ("Parameter ");
260                sb.append (i);
261                sb.append (" : ");
262                sb.append ( paramMgr.getParameter(i) );
263                sb.append (" (dec)");
264                sb.append(System.getProperty("line.separator"));
265            }
266        }
267    }
268
269    private void updateSupportButton() {
270
271        String supportLinkStr = CbusNodeConstants.getModuleSupportLink(paramMgr.getParameter(1),paramMgr.getParameter(3));
272
273        if ( !supportLinkStr.isEmpty() ) {
274            nodesupportlinkbutton.setText(supportLinkStr);
275
276            nodesupportlinkbutton.setToolTipText("<html>" + CbusNodeConstants.getManu(paramMgr.getParameter(1)) +
277                " " + CbusNodeConstants.getModuleType(paramMgr.getParameter(1),paramMgr.getParameter(3)) +
278                " " + Bundle.getMessage("Support") + "</html>");
279
280            try {
281                supportlink=new URI(supportLinkStr);
282                nodesupportlinkbutton.setVisible(true);
283                return;
284            }
285            catch (URISyntaxException ex) {
286                log.warn("Unable to create support link URI for module type {}", paramMgr.getParameter(3), ex);
287            }
288
289        }
290        nodesupportlinkbutton.setVisible(false);
291
292    }
293
294    private static void openUri(URI uri) {
295        if (Desktop.isDesktopSupported()) {
296            try {
297                Desktop.getDesktop().browse(uri);
298            } catch (IOException e) {
299                log.warn("Unable to get URI for {}", uri, e);
300            }
301        }
302    }
303
304    private final static Logger log = LoggerFactory.getLogger(CbusNodeInfoPane.class);
305
306}