001    /*
002     * $Id: StateManager.java,v 1.30 2012/04/30 15:57:35 davep Exp $
003     *
004     * This file is part of McIDAS-V
005     *
006     * Copyright 2007-2012
007     * Space Science and Engineering Center (SSEC)
008     * University of Wisconsin - Madison
009     * 1225 W. Dayton Street, Madison, WI 53706, USA
010     * https://www.ssec.wisc.edu/mcidas
011     * 
012     * All Rights Reserved
013     * 
014     * McIDAS-V is built on Unidata's IDV and SSEC's VisAD libraries, and
015     * some McIDAS-V source code is based on IDV and VisAD source code.  
016     * 
017     * McIDAS-V is free software; you can redistribute it and/or modify
018     * it under the terms of the GNU Lesser Public License as published by
019     * the Free Software Foundation; either version 3 of the License, or
020     * (at your option) any later version.
021     * 
022     * McIDAS-V is distributed in the hope that it will be useful,
023     * but WITHOUT ANY WARRANTY; without even the implied warranty of
024     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
025     * GNU Lesser Public License for more details.
026     * 
027     * You should have received a copy of the GNU Lesser Public License
028     * along with this program.  If not, see http://www.gnu.org/licenses.
029     */
030    
031    package edu.wisc.ssec.mcidasv;
032    
033    import java.awt.event.ActionEvent;
034    import java.io.BufferedReader;
035    import java.io.BufferedWriter;
036    import java.io.FileReader;
037    import java.io.FileWriter;
038    import java.util.Hashtable;
039    import java.util.Properties;
040    
041    import javax.swing.JEditorPane;
042    import javax.swing.JLabel;
043    import javax.swing.JOptionPane;
044    import javax.swing.JPanel;
045    import javax.swing.event.HyperlinkEvent;
046    import javax.swing.event.HyperlinkListener;
047    
048    import ucar.unidata.idv.IdvObjectStore;
049    import ucar.unidata.idv.IntegratedDataViewer;
050    import ucar.unidata.util.IOUtil;
051    import ucar.unidata.util.Misc;
052    import ucar.unidata.util.StringUtil;
053    import edu.wisc.ssec.mcidasv.startupmanager.StartupManager;
054    
055    public class StateManager extends ucar.unidata.idv.StateManager implements Constants, HyperlinkListener {
056            
057            private String version;
058            private String versionAbout;
059            
060            public StateManager(IntegratedDataViewer idv) {
061                    super(idv);
062            }
063            
064            /**
065             * Override to set the right user directory
066             */
067        protected IdvObjectStore doMakeObjectStore() {
068            IdvObjectStore store = new IdvObjectStore(getIdv(),
069                                       getStoreSystemName(), getStoreName(),
070                                       getIdv().getEncoderForRead(),
071                                       StartupManager.INSTANCE.getPlatform().getUserDirectory());
072            initObjectStore(store);
073            return store;
074        }
075    
076            /**
077             * Handle a change to a link
078             *
079             * @param e  the link's event
080             */
081            public void hyperlinkUpdate(HyperlinkEvent e) {
082                    if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
083                            if (e.getURL() == null) {
084                                    click(e.getDescription());
085                            } else {
086                                    click(e.getURL().toString());
087                            }
088                    }
089            }
090            
091            /**
092             * Handle a click on a link
093             *
094             * @param url  the link definition
095             */
096            public void click(String url) {
097                    getIdv().actionPerformed(new ActionEvent(this, 0, url));
098            }
099            
100            public String getOSName() {
101                    String os = System.getProperty("os.name");
102                    os = os.replaceAll(" ", "_");
103                    return os;
104            }
105    
106            public String getMcIdasVersionAbout() {
107            getMcIdasVersion();
108    
109            versionAbout = IOUtil.readContents((String) getProperty(Constants.PROP_ABOUTTEXT), "");
110            versionAbout = StringUtil.replace(versionAbout, MACRO_VERSION, version);
111            Properties props = Misc.readProperties(
112                (String) getProperty(Constants.PROP_VERSIONFILE), 
113                null, 
114                getClass()
115            );
116    
117            String value = getIdvVersion();
118            versionAbout = StringUtil.replace(versionAbout, Constants.MACRO_IDV_VERSION, value);
119            value = props.getProperty(PROP_COPYRIGHT_YEAR, "");
120            versionAbout = StringUtil.replace(versionAbout, Constants.MACRO_COPYRIGHT_YEAR, value);
121            value = props.getProperty(PROP_BUILD_DATE, "Unknown");
122            versionAbout = StringUtil.replace(versionAbout, Constants.MACRO_BUILDDATE, value);
123    
124            return versionAbout;
125            }
126    
127            public String getMcIdasVersion() {
128                    if (version != null) {
129                            return version;
130                    }
131                    
132                    Properties props = new Properties();
133                    props = Misc.readProperties((String) getProperty(Constants.PROP_VERSIONFILE), null, getClass());
134                    String maj = props.getProperty(PROP_VERSION_MAJOR, "0");
135                    String min = props.getProperty(PROP_VERSION_MINOR, "0");
136                    String rel = props.getProperty(PROP_VERSION_RELEASE, "");
137                    
138                    version = maj.concat(".").concat(min).concat(rel);
139                    
140                    return version;
141            }
142    
143        /**
144         * Get a property
145         *
146         * @param name name of the property
147         *
148         * @return  the property or null
149         */
150        @Override public Object getProperty(final String name) {
151            Object value = null;
152            if (McIDASV.isMac())
153                value = getProperties().get("mac."+name);
154    
155            if (value == null) 
156                value = getProperties().get(name);
157    
158            if (value == null) {
159                String fixedName = StateManager.fixIds(name);
160                if (!name.equals(fixedName))
161                    return getProperties().get(fixedName);
162            }
163            return value;
164        }
165    
166        /**
167         * Returns information about the current version of McIDAS-V and the IDV,
168         * along with their respective build dates.
169         * 
170         * @return Hashtable containing versioning information.
171         */
172        public Hashtable<String, String> getVersionInfo() {
173            Properties props = new Properties();
174            props = Misc.readProperties((String) getProperty(Constants.PROP_VERSIONFILE), null, getClass());
175    
176            String mcvBuild = props.getProperty(PROP_BUILD_DATE, "Unknown");
177    
178            Hashtable<String, String> table = new Hashtable<String, String>();
179            table.put("mcv.version.general", getMcIdasVersion());
180            table.put("mcv.version.build", mcvBuild);
181            table.put("idv.version.general", getVersion());
182            table.put("idv.version.build", getBuildDate());
183            return table;
184        }
185    
186            public String getIdvVersion() {
187                    return getVersion();
188            }
189            
190            /**
191             * Overridden to set default of McIDAS-V
192             */
193        public String getStoreSystemName() {
194            return StartupManager.INSTANCE.getPlatform().getUserDirectory();
195        }
196            
197            /**
198             * Overridden to get dir of the unnecessary second level directory.
199             * 
200             * @see ucar.unidata.idv.StateManager#getStoreName()
201             */
202            public String getStoreName() {
203                    return "";
204            }
205            
206            /**
207             * Connect to McIDAS website and look for latest stable version
208             */
209            public String getMcIdasVersionStable() {
210                    String version = "";
211                    try {
212                            version = IOUtil.readContents(Constants.HOMEPAGE_URL+'/'+Constants.VERSION_URL+"?requesting="+getMcIdasVersion()+"&os="+getOSName(), "");
213                    } catch (Exception e) {}
214                    return version.trim();
215            }
216    
217            /**
218             * Connect to McIDAS website and look for latest prerelease version
219             */
220            public String getMcIdasVersionPrerelease() {
221                    String version = "";
222                    try {
223                            String htmlList = IOUtil.readContents(Constants.HOMEPAGE_URL+'/'+Constants.PRERELEASE_URL, "");
224                            String lines[] = htmlList.split("\n");
225                            for (int i=0; i<lines.length; i++) {
226                                    String line = lines[i].trim();
227                                    if (line.matches(".*McIDAS-V_\\d+\\.\\d+.*")) {
228                                            line = line.substring(line.indexOf("McIDAS-V_")+9);
229                                            String aVersion = line.substring(0, line.indexOf("_"));
230                                            if (version == "") {
231                                                    version = aVersion;
232                                            }
233                                            else {
234                                                    int comp = compareVersions(version, aVersion);
235                                                    if (comp > 0) {
236                                                            version = aVersion;
237                                                    }
238                                            }
239                                    }
240                            }
241                    } catch (Exception e) {}
242                    return version.trim();
243            }
244    
245            /**
246             * Connect to McIDAS website and look for latest notice
247             */
248            public String getNoticeLatest() {
249                    String notice = "";
250                    try {
251                            notice = IOUtil.readContents(Constants.HOMEPAGE_URL+"/"+Constants.NOTICE_URL+"?requesting="+getMcIdasVersion()+"&os="+getOSName(), "");
252                    } catch (Exception e) {}
253                    if (notice.indexOf("<notice>")<0) notice="";
254                    notice = notice.replaceAll("<[/?]notice>","");
255                    return notice.trim();
256            }
257    
258            /**
259             * Compare version strings
260             *  0: equal
261             * <0: this version is greater
262             * >0: that version is greater
263             */
264            private int compareVersions(String thisVersion, String thatVersion) {
265                    int thisInt = versionToInteger(thisVersion);            
266                    int thatInt = versionToInteger(thatVersion);
267                    return (thatInt - thisInt);
268            }
269            
270            /**
271             * Turn version strings of the form #.#(a#)
272             *  where # is one or two digits, a is one of alpha or beta, and () is optional
273             * Into an integer... (empty) > beta > alpha
274             */
275            private int versionToInteger(String version) {
276                    int value = 0;
277                    int p;
278                    String part;
279                    Character one = null;
280                    
281                    try {
282                            
283                            // Major version
284                            p = version.indexOf('.');
285                            if (p > 0) {
286                                    part = version.substring(0,p);
287                                    value += Integer.parseInt(part) * 1000000;
288                                    version = version.substring(p+1);
289                            }
290                            
291                            // Minor version
292                            int minor = 0;
293                            int i=0;
294                            for (i=0; i<2 && i<version.length(); i++) {
295                                    one = version.charAt(i);
296                                    if (Character.isDigit(one)) {
297                                            if (i>0) minor *= 10;
298                                            minor += Character.digit(one, 10) * 10000;
299                                    }
300                                    else {
301                                            break;
302                                    }
303                            }
304                            value += minor;
305                            if (one!=null) version = version.substring(i);
306            
307                            // Alpha/beta/update/release status
308                            if (version.length() == 0) value += 300;
309                            else if (version.charAt(0) == 'b') value += 200;
310                            else if (version.charAt(0) == 'a') value += 100;
311                            else if (version.charAt(0) == 'u') value += 400;
312                            else if (version.charAt(0) == 'r') value += 400;
313                            for (i=0; i<version.length(); i++) {
314                                    one = version.charAt(i);
315                                    if (Character.isDigit(one)) break;
316                            }
317                            if (one!=null) version = version.substring(i);
318            
319                            // Alpha/beta version
320                            if (version.length() > 0)
321                                    value += Integer.parseInt(version);
322                            
323                    } catch (Exception e) {}
324                    
325                    return value;
326            }
327            
328            public boolean getIsPrerelease() {
329                    boolean isPrerelease = false;
330                    String version = getMcIdasVersion();
331                    if (version.indexOf("a") >= 0 || version.indexOf("b") >= 0) {
332                            isPrerelease = true;
333                    }
334                    return isPrerelease;
335            }
336            
337            public void checkForNewerVersion(boolean notifyDialog) {
338                    checkForNewerVersionStable(notifyDialog);
339            if (getStore().get(Constants.PREF_PRERELEASE_CHECK, getIsPrerelease())) {
340                    checkForNewerVersionPrerelease(notifyDialog);
341            }
342            }
343            
344            public void checkForNewerVersionStable(boolean notifyDialog) {
345                    
346                    /** Shortcut this whole process if we are processing offscreen */
347                    if (super.getIdv().getArgsManager().getIsOffScreen())
348                            return;
349    
350                    String thisVersion = getMcIdasVersion();
351                    String thatVersion = getMcIdasVersionStable();
352                    String titleText = "Version Check";
353                    
354                    if (thisVersion.equals("") || thatVersion.equals("")) {
355                            if (notifyDialog) {
356                                    JOptionPane.showMessageDialog(null, "Version check failed", titleText, 
357                                                    JOptionPane.WARNING_MESSAGE);
358                            }
359                    }
360                    else if (compareVersions(thisVersion, thatVersion) > 0) {
361                            String labelText = "<html>Version <b>" + thatVersion + "</b> is available<br><br>";
362                            labelText += "Visit <a href=\"" + Constants.HOMEPAGE_URL + "\">";
363                            labelText += Constants.HOMEPAGE_URL + "</a> to download</html>";
364                            
365                            JPanel backgroundColorGetterPanel = new JPanel();
366                            JEditorPane messageText = new JEditorPane("text/html", labelText);
367                            messageText.setBackground(backgroundColorGetterPanel.getBackground());
368                            messageText.setEditable(false);
369                            messageText.addHyperlinkListener(this);
370    
371    //                      JLabel message = new JLabel(labelText, JLabel.CENTER);
372                            JOptionPane.showMessageDialog(null, messageText, titleText, 
373                                            JOptionPane.INFORMATION_MESSAGE);
374                    }
375                    else {
376                            if (notifyDialog) {
377                                    String labelText = "<html>This version (<b>" + thisVersion + "</b>) is up to date</html>";
378                                    JLabel message = new JLabel(labelText, JLabel.CENTER);
379                                    JOptionPane.showMessageDialog(null, message, titleText, 
380                                                    JOptionPane.INFORMATION_MESSAGE);
381                            }
382                    }
383                    
384            }
385            
386            public void checkForNewerVersionPrerelease(boolean notifyDialog) {
387                    
388                    /** Shortcut this whole process if we are processing offscreen */
389                    if (super.getIdv().getArgsManager().getIsOffScreen())
390                            return;
391    
392                    String thisVersion = getMcIdasVersion();
393                    String thatVersion = getMcIdasVersionPrerelease();
394                    String titleText = "Prerelease Check";
395                    
396                    if (thisVersion.equals("") || thatVersion.equals("")) {
397                            if (notifyDialog) {
398                                    JOptionPane.showMessageDialog(null, "No prerelease version available", titleText, 
399                                                    JOptionPane.WARNING_MESSAGE);
400                            }
401                    }
402                    else if (compareVersions(thisVersion, thatVersion) > 0) {
403                            String labelText = "<html>Prerelease <b>" + thatVersion + "</b> is available<br><br>";
404                            labelText += "Visit <a href=\"" + Constants.HOMEPAGE_URL+'/'+Constants.PRERELEASE_URL + "\">";
405                            labelText += Constants.HOMEPAGE_URL+'/'+Constants.PRERELEASE_URL + "</a> to download</html>";
406                            
407                            JPanel backgroundColorGetterPanel = new JPanel();
408                            JEditorPane messageText = new JEditorPane("text/html", labelText);
409                            messageText.setBackground(backgroundColorGetterPanel.getBackground());
410                            messageText.setEditable(false);
411                            messageText.addHyperlinkListener(this);
412    
413    //                      JLabel message = new JLabel(labelText, JLabel.CENTER);
414                            JOptionPane.showMessageDialog(null, messageText, titleText, 
415                                            JOptionPane.INFORMATION_MESSAGE);
416                    }
417                    else {
418                            if (notifyDialog) {
419                                    String labelText = "<html>This version (<b>" + thisVersion + "</b>) is up to date</html>";
420                                    JLabel message = new JLabel(labelText, JLabel.CENTER);
421                                    JOptionPane.showMessageDialog(null, message, titleText, 
422                                                    JOptionPane.INFORMATION_MESSAGE);
423                            }
424                    }
425                    
426            }
427            
428            public void checkForNotice(boolean notifyDialog) {
429                    
430                    /** Shortcut this whole process if we are processing offscreen */
431                    if (super.getIdv().getArgsManager().getIsOffScreen())
432                            return;
433    
434                    String thisNotice = getNoticeCached().trim();
435                    String thatNotice = getNoticeLatest().trim();
436                    String titleText = "New Notice";
437                    String labelText = thatNotice;
438                    
439                    if (thatNotice.equals("")) {
440                            setNoticeCached(thatNotice);
441                            if (notifyDialog) {
442                                    titleText = "No Notice";
443                                    JLabel message = new JLabel("There is no current notice", JLabel.CENTER);
444                                    JOptionPane.showMessageDialog(null, message, titleText, 
445                                                    JOptionPane.INFORMATION_MESSAGE);
446                            }
447                            return;
448                    }
449                    else if (!thisNotice.equals(thatNotice)) {
450                            setNoticeCached(thatNotice);
451                            
452                            JPanel backgroundColorGetterPanel = new JPanel();
453                            JEditorPane messageText = new JEditorPane("text/html", labelText);
454                            messageText.setBackground(backgroundColorGetterPanel.getBackground());
455                            messageText.setEditable(false);
456                            messageText.addHyperlinkListener(this);
457    
458    //                      JLabel message = new JLabel(labelText, JLabel.CENTER);
459                            JOptionPane.showMessageDialog(null, messageText, titleText, 
460                                            JOptionPane.INFORMATION_MESSAGE);
461                    }
462                    else {
463                            if (notifyDialog) {
464                                    titleText = "Previous Notice";
465                                    JLabel message = new JLabel(labelText, JLabel.CENTER);
466                                    JOptionPane.showMessageDialog(null, message, titleText, 
467                                                    JOptionPane.INFORMATION_MESSAGE);
468                            }
469                    }
470                    
471            }
472            
473            private String getNoticePath() {
474            return StartupManager.INSTANCE.getPlatform().getUserFile("notice.txt");
475            }
476    
477            private String getNoticeCached() {
478                String notice = "";
479                    try{
480                            FileReader fstream = new FileReader(getNoticePath());
481                            BufferedReader in = new BufferedReader(fstream);
482                        String line;
483                        while ((line = in.readLine()) != null) {
484                            notice += line + '\n';
485                        }
486                            in.close();
487                    } catch (Exception e){
488                            System.err.println("Error: " + e.getMessage());
489                    }
490                    return notice;
491            }
492            
493            private void setNoticeCached(String notice) {
494                    try{
495                            FileWriter fstream = new FileWriter(getNoticePath());
496                            BufferedWriter out = new BufferedWriter(fstream);
497                            out.write(notice);
498                            out.close();
499                    } catch (Exception e){
500                            System.err.println("Error: " + e.getMessage());
501                    }
502            }
503            
504    }