001/*
002 * This file is part of McIDAS-V
003 *
004 * Copyright 2007-2016
005 * Space Science and Engineering Center (SSEC)
006 * University of Wisconsin - Madison
007 * 1225 W. Dayton Street, Madison, WI 53706, USA
008 * https://www.ssec.wisc.edu/mcidas
009 * 
010 * All Rights Reserved
011 * 
012 * McIDAS-V is built on Unidata's IDV and SSEC's VisAD libraries, and
013 * some McIDAS-V source code is based on IDV and VisAD source code.  
014 * 
015 * McIDAS-V is free software; you can redistribute it and/or modify
016 * it under the terms of the GNU Lesser Public License as published by
017 * the Free Software Foundation; either version 3 of the License, or
018 * (at your option) any later version.
019 * 
020 * McIDAS-V is distributed in the hope that it will be useful,
021 * but WITHOUT ANY WARRANTY; without even the implied warranty of
022 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
023 * GNU Lesser Public License for more details.
024 * 
025 * You should have received a copy of the GNU Lesser Public License
026 * along with this program.  If not, see http://www.gnu.org/licenses.
027 */
028
029package edu.wisc.ssec.mcidasv;
030
031import java.awt.event.ActionEvent;
032import java.io.BufferedReader;
033import java.io.BufferedWriter;
034import java.io.File;
035import java.io.FileReader;
036import java.io.FileWriter;
037import java.util.Hashtable;
038import java.util.Map;
039import java.util.Objects;
040import java.util.Properties;
041
042import javax.swing.JEditorPane;
043import javax.swing.JLabel;
044import javax.swing.JOptionPane;
045import javax.swing.JPanel;
046import javax.swing.event.HyperlinkEvent;
047import javax.swing.event.HyperlinkListener;
048
049import ucar.unidata.idv.IdvObjectStore;
050import ucar.unidata.idv.IntegratedDataViewer;
051import ucar.unidata.util.FileManager;
052import ucar.unidata.util.IOUtil;
053import ucar.unidata.util.LogUtil;
054import ucar.unidata.util.Misc;
055import ucar.unidata.util.StringUtil;
056
057import edu.wisc.ssec.mcidasv.startupmanager.StartupManager;
058import edu.wisc.ssec.mcidasv.util.SystemState;
059
060public class StateManager extends ucar.unidata.idv.StateManager implements Constants, HyperlinkListener {
061
062    public static final String USERPATH_IS_BAD_MESSAGE = "<html>McIDAS-V is unable to create or write to the local user's directory.<br>Please select a directory.</html>";
063
064    public static final String USERPATH_PICK = "Please select a directory to use as the McIDAS-V user path.";
065
066    /** Lazily-loaded VisAD build date. */
067    private String visadDate;
068
069    /** Lazily-loaded VisAD SVN revision number. */
070    private String visadVersion;
071
072    /** Lazily-loaded {@code ncIdv.jar} build timestamp. */
073    private String netcdfDate;
074
075    /** Lazily-loaded {@code ncIdv.jar} version. */
076    private String netcdfVersion;
077
078    private String version;
079    private String versionAbout;
080
081    public StateManager(IntegratedDataViewer idv) {
082        super(idv);
083    }
084
085    /**
086     * Override to set the right user directory.
087     *
088     * @return Newly created object store.
089     */
090    @Override protected IdvObjectStore doMakeObjectStore() {
091        IdvObjectStore store = new IdvObjectStore(getIdv(),
092                                   getStoreSystemName(), getStoreName(),
093                                   getIdv().getEncoderForRead(),
094                                   StartupManager.getInstance().getPlatform().getUserDirectory());
095        initObjectStore(store);
096        return store;
097    }
098
099    /**
100     * Initialize the given object store. This mostly initializes the user's
101     * {@literal "userpath"} directory when it is first created.
102     *
103     * @param store Object store to initialize. Cannot be {@code null}.
104     */
105    @Override protected void initObjectStore(IdvObjectStore store) {
106        while (!store.userDirectoryOk()) {
107            LogUtil.userMessage(USERPATH_IS_BAD_MESSAGE);
108            File dir = FileManager.getDirectory(null, USERPATH_PICK);
109            if (dir != null) {
110                store.setOverrideDirectory(dir);
111            } else {
112                System.exit(0);
113            }
114        }
115
116        if (store.getMadeUserDirectory()) {
117            initNewUserDirectory(store.getUserDirectory());
118        }
119        initUserDirectory(store.getUserDirectory());
120    }
121
122    /**
123     * Handle a change to a link
124     *
125     * @param e  the link's event
126     */
127    @Override public void hyperlinkUpdate(HyperlinkEvent e) {
128        if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
129            if (e.getURL() == null) {
130                click(e.getDescription());
131            } else {
132                click(e.getURL().toString());
133            }
134        }
135    }
136
137    /**
138     * Handle a click on a link
139     *
140     * @param url  the link definition
141     */
142    public void click(String url) {
143        getIdv().actionPerformed(new ActionEvent(this, 0, url));
144    }
145
146    public String getOSName() {
147        String os = System.getProperty("os.name");
148        os = os.replaceAll(" ", "_");
149        return os;
150    }
151
152    public String getMcIdasVersionAbout() {
153        getMcIdasVersion();
154
155        versionAbout = IOUtil.readContents((String) getProperty(Constants.PROP_ABOUTTEXT), "");
156        versionAbout = StringUtil.replace(versionAbout, MACRO_VERSION, version);
157        Properties props = Misc.readProperties(
158            (String) getProperty(Constants.PROP_VERSIONFILE), 
159            null, 
160            getClass()
161        );
162
163        String value = getIdvVersion();
164        versionAbout = StringUtil.replace(versionAbout, Constants.MACRO_IDV_VERSION, value);
165        value = props.getProperty(PROP_COPYRIGHT_YEAR, "");
166        versionAbout = StringUtil.replace(versionAbout, Constants.MACRO_COPYRIGHT_YEAR, value);
167        value = props.getProperty(PROP_BUILD_DATE, "Unknown");
168        versionAbout = StringUtil.replace(versionAbout, Constants.MACRO_BUILDDATE, value);
169        versionAbout = StringUtil.replace(versionAbout, Constants.MACRO_VISAD_VERSION, getVisadVersion());
170        
171        return versionAbout;
172    }
173    
174    public String getMcIdasVersion() {
175        if (version != null) {
176            return version;
177        }
178        
179        Properties props = new Properties();
180        props = Misc.readProperties((String) getProperty(Constants.PROP_VERSIONFILE), null, getClass());
181        String maj = props.getProperty(PROP_VERSION_MAJOR, "0");
182        String min = props.getProperty(PROP_VERSION_MINOR, "0");
183        String rel = props.getProperty(PROP_VERSION_RELEASE, "");
184        
185        version = maj.concat(".").concat(min).concat(rel);
186        
187        return version;
188    }
189    
190    /**
191     * Returns the current Jython version.
192     * 
193     * @return Jython's version information.
194     */
195    @Override public String getJythonVersion() {
196        return org.python.Version.PY_VERSION;
197    }
198    
199    /**
200     * Get a property.
201     *
202     * @param name Name of the property. Cannot be {@code null}.
203     *
204     * @return Value associated with {@code name} or {@code null}.
205     */
206    @Override public Object getProperty(final String name) {
207        Object value = null;
208        if (McIDASV.isMac()) {
209            value = getProperties().get("mac."+name);
210        }
211        if (value == null) {
212            value = getProperties().get(name);
213        }
214        if (value == null) {
215            String fixedName = StateManager.fixIds(name);
216            if (!name.equals(fixedName)) {
217                return getProperties().get(fixedName);
218            }
219        }
220        return value;
221    }
222
223    /**
224     * Find the value associated with the given ID by checking the
225     * {@literal "properties"}, and if nothing was found, check the preferences.
226     *
227     * @param name Property or preference ID. Cannot be {@code null}.
228     *
229     * @return Either the value associated with {@code name} or {@code null}.
230     */
231    public Object getPropertyOrPreference(String name) {
232        Object o = getProperty(name);
233        if (o == null) {
234            o = getPreference(name);
235        }
236        return o;
237    }
238
239    /**
240     * Find the {@link String} value associated with the given ID by checking
241     * the {@literal "properties"}, and if nothing was found, check the
242     * preferences.
243     *
244     * @param name Property or preference ID. Cannot be {@code null}.
245     * @param dflt Value to return if there is no property or preference
246     * associated with {@code name}
247     *
248     * @return Either the value associated with {@code name} or {@code dflt}.
249     */
250    public String getPropertyOrPreference(String name, String dflt) {
251        String value = dflt;
252        Object o = getPropertyOrPreference(name);
253        if (o != null) {
254            value = o.toString();
255        }
256        return value;
257    }
258
259    /**
260     * Find the {@link Integer} value associated with the given ID by checking
261     * the {@literal "properties"}, and if nothing was found, check the
262     * preferences.
263     *
264     * @param name Property or preference ID. Cannot be {@code null}.
265     * @param dflt Value to return if there is no property or preference
266     * associated with {@code name}
267     *
268     * @return Either the value associated with {@code name} or {@code dflt}.
269     */
270    public int getPropertyOrPreference(String name, int dflt) {
271        int value = dflt;
272        Object o = getPropertyOrPreference(name);
273        if (o != null) {
274            value = Integer.valueOf(o.toString());
275        }
276        return value;
277    }
278
279    /**
280     * Find the {@link Double} value associated with the given ID by checking
281     * the {@literal "properties"}, and if nothing was found, check the
282     * preferences.
283     *
284     * @param name Property or preference ID. Cannot be {@code null}.
285     * @param dflt Value to return if there is no property or preference
286     * associated with {@code name}
287     *
288     * @return Either the value associated with {@code name} or {@code dflt}.
289     */
290    public double getPropertyOrPreference(String name, double dflt) {
291        double value = dflt;
292        Object o = getPropertyOrPreference(name);
293        if (o != null) {
294            value = Double.valueOf(o.toString());
295        }
296        return value;
297    }
298
299    /**
300     * Find the {@link Boolean} value associated with the given ID by checking
301     * the {@literal "properties"}, and if nothing was found, check the
302     * preferences.
303     *
304     * @param name Property or preference ID. Cannot be {@code null}.
305     * @param dflt Value to return if there is no property or preference
306     * associated with {@code name}
307     *
308     * @return Either the value associated with {@code name} or {@code dflt}.
309     */
310    public boolean getPropertyOrPreference(String name, boolean dflt) {
311        boolean value = dflt;
312        Object o = getPropertyOrPreference(name);
313        if (o != null) {
314            value = Boolean.valueOf(o.toString());
315        }
316        return value;
317    }
318
319    /**
320     * Returns information about the current version of McIDAS-V and the IDV,
321     * along with their respective build dates.
322     * 
323     * @return {@code Hashtable} containing versioning information.
324     */
325    public Hashtable<String, String> getVersionInfo() {
326        String versionFile = (String)getProperty(Constants.PROP_VERSIONFILE);
327        Properties props =
328            Misc.readProperties(versionFile, null, getClass());
329
330        String mcvBuild = props.getProperty(PROP_BUILD_DATE, "Unknown");
331
332        Hashtable<String, String> table = new Hashtable<>();
333        table.put("mcv.version.general", getMcIdasVersion());
334        table.put("mcv.version.build", mcvBuild);
335        table.put("idv.version.general", getVersion());
336        table.put("idv.version.build", getBuildDate());
337        table.put("visad.version.general", getVisadVersion());
338        table.put("visad.version.build", getVisadDate());
339        table.put("netcdf.version.general", getNetcdfVersion());
340        table.put("netcdf.version.build", getNetcdfDate());
341        return table;
342    }
343
344    /**
345     * Return the timestamp from when {@code ncIdv.jar} was created.
346     *
347     * @return {@code String} representation of the creation timestamp.
348     */
349    public String getNetcdfDate() {
350        if (netcdfDate == null) {
351            Map<String, String> props = SystemState.queryNcidvBuildProperties();
352            netcdfDate = props.get("buildDate");
353            netcdfVersion = props.get("version");
354        }
355        return netcdfDate;
356    }
357
358    /**
359     * Return the version information within {@code ncIdv.jar}.
360     *
361     * @return Version of {@code ncIdv.jar} shipped by McIDAS-V.
362     */
363    public String getNetcdfVersion() {
364        if (netcdfVersion == null) {
365            Map<String, String> props = SystemState.queryNcidvBuildProperties();
366            netcdfDate = props.get("buildDate");
367            netcdfVersion = props.get("version");
368        }
369        return netcdfVersion;
370    }
371
372    /**
373     * Return the timestamp from when visad.jar was created.
374     * 
375     * @return {@code String} representation of the creation timestamp.
376     * Likely to change formatting over time.
377     */
378    public String getVisadDate() {
379        if (visadDate == null) {
380            Map<String, String> props = SystemState.queryVisadBuildProperties();
381            visadDate = props.get(Constants.PROP_VISAD_DATE);
382            visadVersion = props.get(Constants.PROP_VISAD_REVISION);
383        }
384        return visadDate;
385    }
386
387    /**
388     * Return the {@literal "version"} of VisAD.
389     * 
390     * @return Currently returns whatever the SVN revision number was when
391     * visad.jar was built. 
392     */
393    public String getVisadVersion() {
394        if (visadVersion == null) {
395            Map<String, String> props = SystemState.queryVisadBuildProperties();
396            visadDate = props.get(Constants.PROP_VISAD_DATE);
397            visadVersion = props.get(Constants.PROP_VISAD_REVISION);
398        }
399        return visadVersion;
400    }
401
402    public String getIdvVersion() {
403        return getVersion();
404    }
405
406    /**
407     * Overridden to set default of McIDAS-V
408     */
409    @Override public String getStoreSystemName() {
410        return StartupManager.getInstance().getPlatform().getUserDirectory();
411    }
412
413    /**
414     * Overridden to get dir of the unnecessary second level directory.
415     */
416    @Override public String getStoreName() {
417        return "";
418    }
419
420    /**
421     * Connect to McIDAS-V website and look for latest stable version.
422     *
423     * @return Latest stable version.
424     */
425    public String getMcIdasVersionStable() {
426        String offscreen = "0";
427        if (super.getIdv().getArgsManager().getIsOffScreen()) {
428            offscreen = "1";
429        }
430
431        String version = "";
432        try {
433            version = IOUtil.readContents(Constants.HOMEPAGE_URL+"/"+Constants.VERSION_HANDLER_URL+"?v="+getMcIdasVersion()+"&os="+getOSName()+"&off="+offscreen, "");
434        } catch (Exception e) {}
435        return version.trim();
436    }
437
438    /**
439     * Connect to McIDAS-V website and look for latest pre-release version.
440     *
441     * @return Latest pre-release version.
442     */
443    public String getMcIdasVersionPrerelease() {
444        String version = "";
445        try {
446            String htmlList = IOUtil.readContents(Constants.HOMEPAGE_URL+'/'+Constants.PRERELEASE_URL, "");
447            String lines[] = htmlList.split("\n");
448            for (int i=0; i<lines.length; i++) {
449                String line = lines[i].trim();
450                if (line.matches(".*McIDAS-V_\\d+\\.\\d+.*")) {
451                    line = line.substring(line.indexOf("McIDAS-V_")+9);
452                    String aVersion = line.substring(0, line.indexOf("_"));
453                    if (version.isEmpty()) {
454                        version = aVersion;
455                    }
456                    else {
457                        int comp = compareVersions(version, aVersion);
458                        if (comp > 0) {
459                            version = aVersion;
460                        }
461                    }
462                }
463            }
464        } catch (Exception e) {}
465        return version.trim();
466    }
467
468    /**
469     * Connect to McIDAS website and look for latest notice.
470     *
471     * @return Contents of notice. String may be empty.
472     */
473    public String getNoticeLatest() {
474        String notice = "";
475        try {
476            notice = IOUtil.readContents(Constants.HOMEPAGE_URL+"/"+Constants.NOTICE_URL+"?requesting="+getMcIdasVersion()+"&os="+getOSName(), "");
477        } catch (Exception e) {}
478        if (notice.indexOf("<notice>")<0) notice="";
479        notice = notice.replaceAll("<[/?]notice>","");
480        return notice.trim();
481    }
482
483    /**
484     * Compare version strings.
485     *
486     * <p>The logic is as follows.
487     * <pre>
488     *    0: thisVersion and thatVersion are equal.
489     *   &lt;0: thisVersion is greater.
490     *   &gt;0: thatVersion is greater.
491     * </pre>
492     *
493     * @param thisVersion First version string to compare.
494     * @param thatVersion Second version string to compare.
495     *
496     * @return Value indicating which of {@code thisVersion} and
497     * {@code thatVersion} is {@literal "greater"}.
498     */
499    public static int compareVersions(String thisVersion, String thatVersion) {
500        int thisInt = versionToInteger(thisVersion);
501        int thatInt = versionToInteger(thatVersion);
502        return thatInt - thisInt;
503    }
504
505    /**
506     * Turn version strings of the form {@code #.#(a#)}, where # is one or two
507     * digits, a is one of alpha or beta, and () is optional, into an integer
508     * value... (empty) &gt; beta &gt; alpha.
509     *
510     * @param version String representation of version number.
511     *
512     * @return Integer representation of {@code version}.
513     */
514        public static int versionToInteger(String version) {
515                int value = 0;
516                int p;
517                String part;
518                Character one = null;
519                
520                try {
521                        
522                        // Major version
523                        p = version.indexOf('.');
524                        if (p > 0) {
525                                part = version.substring(0,p);
526                                value += Integer.parseInt(part) * 1000000;
527                                version = version.substring(p+1);
528                        }
529                        
530                        // Minor version
531                        int minor = 0;
532                        int i=0;
533                        for (i=0; i<2 && i<version.length(); i++) {
534                                one = version.charAt(i);
535                                if (Character.isDigit(one)) {
536                                        if (i>0) minor *= 10;
537                                        minor += Character.digit(one, 10) * 10000;
538                                }
539                                else {
540                                        break;
541                                }
542                        }
543                        value += minor;
544                        if (one!=null) version = version.substring(i);
545        
546                        // Alpha/beta/update/release status
547                        if (version.length() == 0) value += 300;
548                        else if (version.charAt(0) == 'b') value += 200;
549                        else if (version.charAt(0) == 'a') value += 100;
550                        else if (version.charAt(0) == 'u') value += 400;
551                        else if (version.charAt(0) == 'r') value += 400;
552                        for (i=0; i<version.length(); i++) {
553                                one = version.charAt(i);
554                                if (Character.isDigit(one)) break;
555                        }
556                        if (one!=null) version = version.substring(i);
557        
558                        // Alpha/beta version
559                        if (version.length() > 0)
560                                value += Integer.parseInt(version);
561                        
562                } catch (Exception e) {}
563                
564                return value;
565        }
566        
567        public boolean getIsPrerelease() {
568                boolean isPrerelease = false;
569                String version = getMcIdasVersion();
570                if (version.indexOf("a") >= 0 || version.indexOf("b") >= 0) {
571                        isPrerelease = true;
572                }
573                return isPrerelease;
574        }
575        
576        public void checkForNewerVersion(boolean notifyDialog) {
577                checkForNewerVersionStable(notifyDialog);
578        if (getStore().get(Constants.PREF_PRERELEASE_CHECK, getIsPrerelease())) {
579                checkForNewerVersionPrerelease(notifyDialog);
580        }
581        }
582        
583        public void checkForNewerVersionStable(boolean notifyDialog) {
584
585                /** Get the stable version from the website (for statistics recording) */
586                String thatVersion = getMcIdasVersionStable();
587
588                /** Shortcut the rest of the process if we are processing offscreen */
589                if (super.getIdv().getArgsManager().getIsOffScreen()) {
590                        return;
591                }
592
593                String thisVersion = getMcIdasVersion();
594                String titleText = "Version Check";
595                
596                if (thisVersion.equals("") || thatVersion.equals("")) {
597                        if (notifyDialog) {
598                                JOptionPane.showMessageDialog(null, "Version check failed", titleText, 
599                                                JOptionPane.WARNING_MESSAGE);
600                        }
601                }
602                else if (compareVersions(thisVersion, thatVersion) > 0) {
603                        String labelText = "<html>Version <b>" + thatVersion + "</b> is available<br><br>";
604                        labelText += "Visit <a href=\"" + Constants.HOMEPAGE_URL + "\">";
605                        labelText += Constants.HOMEPAGE_URL + "</a> to download</html>";
606                        
607                        JPanel backgroundColorGetterPanel = new JPanel();
608                        JEditorPane messageText = new JEditorPane("text/html", labelText);
609                        messageText.setBackground(backgroundColorGetterPanel.getBackground());
610                        messageText.setEditable(false);
611                        messageText.addHyperlinkListener(this);
612
613//                      JLabel message = new JLabel(labelText, JLabel.CENTER);
614                        JOptionPane.showMessageDialog(null, messageText, titleText, 
615                                        JOptionPane.INFORMATION_MESSAGE);
616                }
617                else {
618                        if (notifyDialog) {
619                                String labelText = "<html>This version (<b>" + thisVersion + "</b>) is up to date</html>";
620                                JLabel message = new JLabel(labelText, JLabel.CENTER);
621                                JOptionPane.showMessageDialog(null, message, titleText, 
622                                                JOptionPane.INFORMATION_MESSAGE);
623                        }
624                }
625                
626        }
627        
628        public void checkForNewerVersionPrerelease(boolean notifyDialog) {
629                
630                /** Shortcut the rest of the process if we are processing offscreen */
631                if (super.getIdv().getArgsManager().getIsOffScreen()) {
632                        return;
633                }
634
635                String thisVersion = getMcIdasVersion();
636                String thatVersion = getMcIdasVersionPrerelease();
637                String titleText = "Prerelease Check";
638                
639                if (thisVersion.equals("") || thatVersion.equals("")) {
640                        if (notifyDialog) {
641                                JOptionPane.showMessageDialog(null, "No prerelease version available", titleText, 
642                                                JOptionPane.WARNING_MESSAGE);
643                        }
644                }
645                else if (compareVersions(thisVersion, thatVersion) > 0) {
646                        String labelText = "<html>Prerelease <b>" + thatVersion + "</b> is available<br><br>";
647                        labelText += "Visit <a href=\"" + Constants.HOMEPAGE_URL+'/'+Constants.PRERELEASE_URL + "\">";
648                        labelText += Constants.HOMEPAGE_URL+'/'+Constants.PRERELEASE_URL + "</a> to download</html>";
649                        
650                        JPanel backgroundColorGetterPanel = new JPanel();
651                        JEditorPane messageText = new JEditorPane("text/html", labelText);
652                        messageText.setBackground(backgroundColorGetterPanel.getBackground());
653                        messageText.setEditable(false);
654                        messageText.addHyperlinkListener(this);
655
656//                      JLabel message = new JLabel(labelText, JLabel.CENTER);
657                        JOptionPane.showMessageDialog(null, messageText, titleText, 
658                                        JOptionPane.INFORMATION_MESSAGE);
659                }
660                else {
661                        if (notifyDialog) {
662                                String labelText = "<html>This version (<b>" + thisVersion + "</b>) is up to date</html>";
663                                JLabel message = new JLabel(labelText, JLabel.CENTER);
664                                JOptionPane.showMessageDialog(null, message, titleText, 
665                                                JOptionPane.INFORMATION_MESSAGE);
666                        }
667                }
668                
669        }
670
671    public void checkForNotice(boolean notifyDialog) {
672
673        // Shortcut this whole process if we are processing offscreen
674        if (super.getIdv().getArgsManager().getIsOffScreen()) {
675            return;
676        }
677
678        String thisNotice = getNoticeCached().trim();
679        String thatNotice = getNoticeLatest().trim();
680        String titleText = "New Notice";
681        String labelText = thatNotice;
682
683        if (thatNotice.equals("")) {
684            setNoticeCached(thatNotice);
685            if (notifyDialog) {
686                titleText = "No Notice";
687                JLabel message = new JLabel("There is no current notice", JLabel.CENTER);
688                JOptionPane.showMessageDialog(null, message, titleText,
689                    JOptionPane.INFORMATION_MESSAGE);
690            }
691            return;
692        } else if (!thisNotice.equals(thatNotice)) {
693            setNoticeCached(thatNotice);
694
695            JPanel backgroundColorGetterPanel = new JPanel();
696            JEditorPane messageText = new JEditorPane("text/html", labelText);
697            messageText.setBackground(backgroundColorGetterPanel.getBackground());
698            messageText.setEditable(false);
699            messageText.addHyperlinkListener(this);
700            JOptionPane.showMessageDialog(null, messageText, titleText,
701                JOptionPane.INFORMATION_MESSAGE);
702        } else {
703            if (notifyDialog) {
704                titleText = "Previous Notice";
705                JPanel bgPanel = new JPanel();
706                JEditorPane messageText =
707                    new JEditorPane("text/html", labelText);
708                messageText.setBackground(bgPanel.getBackground());
709                messageText.setEditable(false);
710                messageText.addHyperlinkListener(this);
711                JOptionPane.showMessageDialog(null, messageText, titleText,
712                    JOptionPane.INFORMATION_MESSAGE);
713            }
714        }
715    }
716
717    /**
718     * Debug a McIDAS-V {@literal "system notice"} before sending it to all
719     * users!
720     *
721     * @param noticeContents Contents of the notice.
722     * @param notifyDialog if {@code true}, show notice even if already seen.
723     * @param disableCache Whether or not {@code noticeContents} will be cached.
724     */
725    public void debugNotice(String noticeContents, boolean notifyDialog,
726                            boolean disableCache)
727    {
728        // Shortcut this whole process if we are processing offscreen
729        if (super.getIdv().getArgsManager().getIsOffScreen()) {
730            return;
731        }
732
733        String thisNotice;
734        thisNotice = disableCache ? "" : getNoticeCached().trim();
735        String thatNotice = noticeContents.trim();
736        String labelText = thatNotice;
737
738        if (thatNotice.isEmpty()) {
739            if (!disableCache) {
740                setNoticeCached(thatNotice);
741            }
742            if (notifyDialog) {
743                String titleText = "No Notice";
744                JLabel message = new JLabel("There is no current notice", JLabel.CENTER);
745                JOptionPane.showMessageDialog(null, message, titleText,
746                    JOptionPane.INFORMATION_MESSAGE);
747            }
748        } else if (!thisNotice.equals(thatNotice)) {
749            if (!disableCache) {
750                setNoticeCached(thatNotice);
751            }
752            String titleText = "New Notice";
753            JPanel backgroundColorGetterPanel = new JPanel();
754            JEditorPane messageText = new JEditorPane("text/html", labelText);
755            messageText.setBackground(backgroundColorGetterPanel.getBackground());
756            messageText.setEditable(false);
757            messageText.addHyperlinkListener(this);
758            JOptionPane.showMessageDialog(null, messageText, titleText,
759                JOptionPane.INFORMATION_MESSAGE);
760        } else {
761            if (notifyDialog) {
762                String titleText = "Previous Notice";
763                JPanel bgPanel = new JPanel();
764                JEditorPane messageText =
765                    new JEditorPane("text/html", labelText);
766                messageText.setBackground(bgPanel.getBackground());
767                messageText.setEditable(false);
768                messageText.addHyperlinkListener(this);
769                JOptionPane.showMessageDialog(null, messageText, titleText,
770                    JOptionPane.INFORMATION_MESSAGE);
771            }
772        }
773    }
774
775    private String getNoticePath() {
776        return StartupManager.getInstance().getPlatform().getUserFile("notice.txt");
777    }
778
779    private String getNoticeCached() {
780        String notice = "";
781        try{
782            FileReader fstream = new FileReader(getNoticePath());
783            BufferedReader in = new BufferedReader(fstream);
784            String line;
785            while ((line = in.readLine()) != null) {
786                notice += line + '\n';
787            }
788            in.close();
789        } catch (Exception e){
790            System.err.println("Error: " + e.getMessage());
791        }
792        return notice;
793    }
794
795    private void setNoticeCached(String notice) {
796        try{
797            FileWriter fstream = new FileWriter(getNoticePath());
798            BufferedWriter out = new BufferedWriter(fstream);
799            out.write(notice);
800            out.close();
801        } catch (Exception e){
802            System.err.println("Error: " + e.getMessage());
803        }
804    }
805}