001/*
002 * $Id: StateManager.java,v 1.28 2011/03/24 16:06:31 davep Exp $
003 *
004 * This file is part of McIDAS-V
005 *
006 * Copyright 2007-2011
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
031package edu.wisc.ssec.mcidasv;
032
033import java.awt.event.ActionEvent;
034import java.io.BufferedReader;
035import java.io.BufferedWriter;
036import java.io.FileReader;
037import java.io.FileWriter;
038import java.util.Hashtable;
039import java.util.Properties;
040
041import javax.swing.JEditorPane;
042import javax.swing.JLabel;
043import javax.swing.JOptionPane;
044import javax.swing.JPanel;
045import javax.swing.event.HyperlinkEvent;
046import javax.swing.event.HyperlinkListener;
047
048import ucar.unidata.idv.IdvObjectStore;
049import ucar.unidata.idv.IntegratedDataViewer;
050import ucar.unidata.util.IOUtil;
051import ucar.unidata.util.Misc;
052import ucar.unidata.util.StringUtil;
053import edu.wisc.ssec.mcidasv.startupmanager.StartupManager;
054
055public 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//                                      if (i==0) value += Character.digit(one, 10) * 100000;
300//                                      else value += Character.digit(one, 10) * 10000;
301                                }
302                                else {
303                                        break;
304                                }
305                        }
306                        value += minor;
307                        if (one!=null) version = version.substring(i);
308        
309                        // Alpha/beta status
310                        if (version.length() == 0) value += 300;
311                        else if (version.charAt(0) == 'b') value += 200;
312                        else if (version.charAt(0) == 'a') value += 100;
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}