001package jmri.jmrix.openlcb.swing.lccpro;
002
003import java.awt.*;
004
005import java.beans.PropertyChangeEvent;
006import java.beans.PropertyChangeListener;
007import java.awt.event.WindowEvent;
008
009import java.io.File;
010import java.io.IOException;
011
012import javax.swing.*;
013
014import jmri.*;
015import jmri.jmrix.can.CanSystemConnectionMemo;
016import jmri.util.swing.JmriJOptionPane;
017
018import org.openlcb.*;
019import org.openlcb.cdi.impl.ConfigRepresentation;
020
021/**
022 * Do a backup of a specified node.
023 *
024 * Not truly an Action, though it might be some day
025 * @author Bob Jacobsen   (c) 2026
026 */
027
028
029class NodeBackupAction {
030
031    private ConfigRepresentation _cdi;
032    private String _name;
033    
034    static JFileChooser directoryChooser = new JFileChooser();
035    static final String PREFNAME = "backupDirectory";
036    
037    static boolean fileConfigured;
038    
039    static {
040        directoryChooser.setFileSelectionMode(javax.swing.JFileChooser.DIRECTORIES_ONLY);
041        directoryChooser.setDialogTitle(Bundle.getMessage("ChooseADirectory"));
042        directoryChooser.setSelectedFile(new File("."));
043        
044        var prefsMgr = InstanceManager.getDefault(UserPreferencesManager.class);
045        var dirPref = prefsMgr.getProperty(NodeBackupAction.class.getName(), PREFNAME);
046        if (dirPref != null) {
047            directoryChooser.setSelectedFile(new File(dirPref.toString()));
048            fileConfigured = true;
049        } else {
050            fileConfigured = false;
051        }
052
053    }
054    
055    public static void showOpenDialog(Component here) {
056        var response = directoryChooser.showOpenDialog(here);
057        
058        if (response == JFileChooser.APPROVE_OPTION) {
059            String directory = directoryChooser.getSelectedFile().getAbsolutePath();
060            var prefsMgr = InstanceManager.getDefault(UserPreferencesManager.class);
061            prefsMgr.setProperty(NodeBackupAction.class.getName(), PREFNAME, directory);
062            fileConfigured = true;
063        }
064    }
065    
066    public void doBackup(MimicNodeStore.NodeMemo nodememo, CanSystemConnectionMemo memo, String name) {
067        
068        if (!fileConfigured) {
069            showOpenDialog(null); // no Component in this case
070        }
071        
072        var node = nodememo.getNodeID();
073        _name = name;
074        log.info("Backup {} '{}' ", node.toString(), _name);    
075        
076        var iface = memo.get(OlcbInterface.class);
077        
078        _cdi = iface.getConfigForNode(node);
079               
080        // always show the status
081        JmriJOptionPane.showMessageDialogNonModal(null,
082                Bundle.getMessage("MessageCdiLoad", _name, node),
083                Bundle.getMessage("TitleCdiLoad", name),
084                JmriJOptionPane.INFORMATION_MESSAGE,
085                null);
086
087        if (_cdi.getRoot() != null) {
088            // configuration cache present, store and
089            // cancel window after short delay
090            storeCdiData();
091            jmri.util.ThreadingUtil.runOnGUIDelayed(() -> {
092                closeStatusWindow();
093                }, 1000); 
094
095        } else {
096            // configuration cache present, wait for it
097            // to arrive
098            _cdi.addPropertyChangeListener(new CdiListener());
099        }
100    }
101    
102    // close the progress window and save the contents 
103    // when the CDI has been completely read
104    private class CdiListener implements PropertyChangeListener {
105        @Override
106        public void propertyChange(PropertyChangeEvent e) {
107            String propertyName = e.getPropertyName();
108            log.debug("CdiListener event = {}", propertyName);
109
110            if (propertyName.equals("UPDATE_CACHE_COMPLETE")) {
111                closeStatusWindow();
112                storeCdiData();
113            }
114        }
115    }
116    
117    protected void closeStatusWindow() {
118        Window[] windows = Window.getWindows();
119        for (Window window : windows) {
120            if (window instanceof JDialog) {
121                JDialog dialog = (JDialog) window;
122                if (Bundle.getMessage("TitleCdiLoad", _name).equals(dialog.getTitle())) {
123                    dialog.dispatchEvent(new WindowEvent(dialog, WindowEvent.WINDOW_CLOSING));
124                }
125            }
126        }
127    }
128    
129    protected void storeCdiData() {
130        log.debug("Load complete");
131        var filename = org.openlcb.cdi.swing.CdiPanel
132                        .fileNameGenerator.generateFileName(_cdi, _name);
133        String directory = directoryChooser.getSelectedFile().getAbsolutePath();
134        String storeName = directory+File.separator+filename;
135        log.info("Storing to file {}", storeName);
136        try {
137            org.openlcb.cdi.cmd.BackupConfig.writeConfigToFile(storeName, _cdi);
138        } catch (IOException e) {
139            log.error("Error writing file! ", e);
140        }
141        
142    }
143
144    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(NodeBackupAction.class);
145}