001    // License: GPL. For details, see LICENSE file.
002    package org.openstreetmap.josm.data.imagery;
003    
004    import java.io.IOException;
005    import java.util.ArrayList;
006    import java.util.Arrays;
007    import java.util.Collection;
008    import java.util.Collections;
009    import java.util.LinkedList;
010    import java.util.List;
011    
012    import org.openstreetmap.josm.Main;
013    import org.openstreetmap.josm.data.imagery.ImageryInfo.ImageryPreferenceEntry;
014    import org.openstreetmap.josm.io.imagery.ImageryReader;
015    import org.openstreetmap.josm.io.MirroredInputStream;
016    import org.openstreetmap.josm.tools.Utils;
017    import org.xml.sax.SAXException;
018    
019    /**
020     * Manages the list of imagery entries that are shown in the imagery menu.
021     */
022    public class ImageryLayerInfo {
023    
024        public static final ImageryLayerInfo instance = new ImageryLayerInfo();
025        ArrayList<ImageryInfo> layers = new ArrayList<ImageryInfo>();
026        static ArrayList<ImageryInfo> defaultLayers = new ArrayList<ImageryInfo>();
027    
028        private final static String[] DEFAULT_LAYER_SITES = {
029            "http://josm.openstreetmap.de/maps"
030        };
031    
032        private ImageryLayerInfo() {
033        }
034    
035        public ImageryLayerInfo(ImageryLayerInfo info) {
036            layers.addAll(info.layers);
037        }
038    
039        public void clear() {
040            layers.clear();
041        }
042    
043        public void load() {
044            boolean addedDefault = layers.size() != 0;
045            List<ImageryPreferenceEntry> entries = Main.pref.getListOfStructs("imagery.entries", null, ImageryPreferenceEntry.class);
046            if (entries != null) {
047                for (ImageryPreferenceEntry prefEntry : entries) {
048                    try {
049                        ImageryInfo i = new ImageryInfo(prefEntry);
050                        add(i);
051                    } catch (IllegalArgumentException e) {
052                        System.err.println("Warning: Unable to load imagery preference entry:"+e);
053                    }
054                }
055                Collections.sort(layers);
056            }
057            if (addedDefault) {
058                save();
059            }
060        }
061    
062        public void loadDefaults(boolean clearCache) {
063            defaultLayers.clear();
064            for (String source : Main.pref.getCollection("imagery.layers.sites", Arrays.asList(DEFAULT_LAYER_SITES))) {
065                if (clearCache) {
066                    MirroredInputStream.cleanup(source);
067                }
068                MirroredInputStream stream = null;
069                try {
070                    ImageryReader reader = new ImageryReader(source);
071                    Collection<ImageryInfo> result = reader.parse();
072                    defaultLayers.addAll(result);
073                } catch (IOException ex) {
074                    Utils.close(stream);
075                    ex.printStackTrace();
076                    continue;
077                } catch (SAXException sex) {
078                    Utils.close(stream);
079                    sex.printStackTrace();
080                    continue;
081                }
082            }
083            while (defaultLayers.remove(null)) {}
084    
085            Collection<String> defaults = Main.pref.getCollection("imagery.layers.default");
086            ArrayList<String> defaultsSave = new ArrayList<String>();
087            for (ImageryInfo def : defaultLayers) {
088                if (def.isDefaultEntry()) {
089                    defaultsSave.add(def.getUrl());
090    
091                    boolean isKnownDefault = false;
092                    for (String url : defaults) {
093                        if (isSimilar(url, def.getUrl())) {
094                            isKnownDefault = true;
095                            break;
096                        }
097                    }
098                    boolean isInUserList = false;
099                    if (!isKnownDefault) {
100                        for (ImageryInfo i : layers) {
101                            if (isSimilar(def.getUrl(), i.getUrl())) {
102                                isInUserList = true;
103                                break;
104                            }
105                        }
106                    }
107                    if (!isKnownDefault && !isInUserList) {
108                        add(new ImageryInfo(def));
109                    }
110                }
111            }
112    
113            Collections.sort(defaultLayers);
114            Main.pref.putCollection("imagery.layers.default", defaultsSave.size() > 0
115                    ? defaultsSave : defaults);
116        }
117    
118        // some additional checks to respect extended URLs in preferences (legacy workaround)
119        private boolean isSimilar(String a, String b) {
120            return Utils.equal(a, b) || (a != null && b != null && !"".equals(a) && !"".equals(b) && (a.contains(b) || b.contains(a)));
121        }
122    
123        public void add(ImageryInfo info) {
124            layers.add(info);
125        }
126    
127        public void remove(ImageryInfo info) {
128            layers.remove(info);
129        }
130    
131        public void save() {
132            List<ImageryPreferenceEntry> entries = new ArrayList<ImageryPreferenceEntry>();
133            for (ImageryInfo info : layers) {
134                entries.add(new ImageryPreferenceEntry(info));
135            }
136            Main.pref.putListOfStructs("imagery.entries", entries, ImageryPreferenceEntry.class);
137        }
138    
139        public List<ImageryInfo> getLayers() {
140            return Collections.unmodifiableList(layers);
141        }
142    
143        public List<ImageryInfo> getDefaultLayers() {
144            return Collections.unmodifiableList(defaultLayers);
145        }
146    
147        public static void addLayer(ImageryInfo info) {
148            instance.add(info);
149            instance.save();
150            Main.main.menu.imageryMenu.refreshImageryMenu();
151        }
152    
153        public static void addLayers(Collection<ImageryInfo> infos) {
154            for (ImageryInfo i : infos) {
155                instance.add(i);
156            }
157            instance.save();
158            Collections.sort(instance.layers);
159            Main.main.menu.imageryMenu.refreshImageryMenu();
160        }
161    }