001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.gui.dialogs.properties;
003
004import java.util.ArrayList;
005import java.util.Iterator;
006import java.util.LinkedHashMap;
007import java.util.List;
008import java.util.Map;
009
010import org.openstreetmap.josm.actions.search.SearchAction;
011import org.openstreetmap.josm.actions.search.SearchCompiler;
012import org.openstreetmap.josm.data.osm.Tag;
013import org.openstreetmap.josm.data.preferences.CollectionProperty;
014
015class RecentTagCollection {
016
017    private final Map<Tag, Void> recentTags;
018    private SearchCompiler.Match tagsToIgnore;
019
020    RecentTagCollection(final int capacity) {
021        // LRU cache for recently added tags (http://java-planet.blogspot.com/2005/08/how-to-set-up-simple-lru-cache-using.html)
022        recentTags = new LinkedHashMap<Tag, Void>(capacity + 1, 1.1f, true) {
023            @Override
024            protected boolean removeEldestEntry(Map.Entry<Tag, Void> eldest) {
025                return size() > capacity;
026            }
027        };
028        tagsToIgnore = new SearchCompiler.Never();
029    }
030
031    public void loadFromPreference(CollectionProperty property) {
032        recentTags.clear();
033        Iterator<String> it = property.get().iterator();
034        while (it.hasNext()) {
035            String key = it.next();
036            String value = it.next();
037            add(new Tag(key, value));
038        }
039    }
040
041    public void saveToPreference(CollectionProperty property) {
042        List<String> c = new ArrayList<>(recentTags.size() * 2);
043        for (Tag t : recentTags.keySet()) {
044            c.add(t.getKey());
045            c.add(t.getValue());
046        }
047        property.put(c);
048    }
049
050    public void add(Tag tag) {
051        if (!tagsToIgnore.match(tag)) {
052            recentTags.put(tag, null);
053        }
054    }
055
056    public boolean isEmpty() {
057        return recentTags.isEmpty();
058    }
059
060    public List<Tag> toList() {
061        return new ArrayList<>(recentTags.keySet());
062    }
063
064    public void setTagsToIgnore(SearchCompiler.Match tagsToIgnore) {
065        this.tagsToIgnore = tagsToIgnore;
066        final Iterator<Tag> it = recentTags.keySet().iterator();
067        while (it.hasNext()) {
068            if (tagsToIgnore.match(it.next())) {
069                it.remove();
070            }
071        }
072    }
073
074    public void setTagsToIgnore(SearchAction.SearchSetting tagsToIgnore) throws SearchCompiler.ParseError {
075        setTagsToIgnore(tagsToIgnore.text.isEmpty() ? new SearchCompiler.Never() : SearchCompiler.compile(tagsToIgnore));
076    }
077
078    public SearchAction.SearchSetting ignoreTag(Tag tagToIgnore, SearchAction.SearchSetting settingToUpdate) throws SearchCompiler.ParseError {
079        final String forTag = SearchCompiler.buildSearchStringForTag(tagToIgnore.getKey(), tagToIgnore.getValue());
080        settingToUpdate.text = settingToUpdate.text.isEmpty()
081                ? forTag
082                : settingToUpdate.text + " OR " + forTag;
083        setTagsToIgnore(settingToUpdate);
084        return settingToUpdate;
085    }
086}