001/*
002 * Gridarta MMORPG map editor for Crossfire, Daimonin and similar games.
003 * Copyright (C) 2000-2011 The Gridarta Developers.
004 *
005 * This program is free software; you can redistribute it and/or modify
006 * it under the terms of the GNU General Public License as published by
007 * the Free Software Foundation; either version 2 of the License, or
008 * (at your option) any later version.
009 *
010 * This program is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
013 * GNU General Public License for more details.
014 *
015 * You should have received a copy of the GNU General Public License along
016 * with this program; if not, write to the Free Software Foundation, Inc.,
017 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
018 */
019
020package net.sf.gridarta.gui.dialog.plugin.parameter;
021
022import java.util.ArrayList;
023import java.util.Collection;
024import java.util.Collections;
025import java.util.Comparator;
026import java.util.List;
027import javax.swing.AbstractListModel;
028import javax.swing.ComboBoxModel;
029import net.sf.gridarta.model.archetype.Archetype;
030import net.sf.gridarta.model.archetypeset.ArchetypeSet;
031import net.sf.gridarta.model.gameobject.GameObject;
032import net.sf.gridarta.model.maparchobject.MapArchObject;
033import org.jetbrains.annotations.NotNull;
034import org.jetbrains.annotations.Nullable;
035
036public class ArchComboBoxModel<G extends GameObject<G, A, R>, A extends MapArchObject<A>, R extends Archetype<G, A, R>> extends AbstractListModel implements ComboBoxModel {
037
038    @Nullable
039    private Object value;
040
041    @NotNull
042    private final List<Archetype<G, A, R>> archList;
043
044    // FIXME: This constant looks pretty pointless.
045
046    @NotNull
047    private static final String CURRENT_FILTER = "";
048
049    private static final long serialVersionUID = 1L;
050
051    public ArchComboBoxModel(@NotNull final ArchetypeSet<G, A, R> archetypeSet) {
052        final Collection<R> archetypes = archetypeSet.getArchetypes();
053        archList = new ArrayList<Archetype<G, A, R>>(archetypes);
054        Collections.sort(archList, new Comparator<Archetype<G, A, R>>() {
055
056            @Override
057            public int compare(final Archetype<G, A, R> o1, final Archetype<G, A, R> o2) {
058                return o1.getArchetypeName().toLowerCase().compareTo(o2.getArchetypeName().toLowerCase());
059            }
060        });
061    }
062
063    @Nullable
064    @Override
065    public Object getSelectedItem() {
066        return value;
067    }
068
069    @Override
070    public void setSelectedItem(final Object anItem) {
071        value = anItem;
072    }
073
074    @Override
075    public int getSize() {
076        return archList.size();
077    }
078
079    @NotNull
080    @Override
081    public Object getElementAt(final int index) {
082        return archList.get(index);
083    }
084
085    public void setFilter(@NotNull final String filter) {
086        if (filter.startsWith(CURRENT_FILTER)) {
087            narrowFilter(filter);
088        } else if (CURRENT_FILTER.startsWith(filter)) {
089            enlargeFilter(filter);
090        } else {
091            final int p = getCommonPrefix(CURRENT_FILTER, filter);
092            enlargeFilter(filter.substring(0, p));
093            narrowFilter(filter);
094        }
095        fireContentsChanged(this, 0, archList.size());
096    }
097
098    private static int getCommonPrefix(@NotNull final CharSequence s1, @NotNull final CharSequence s2) {
099        int i = 0;
100        while (s1.length() > i && s2.length() > i && s1.charAt(i) == s2.charAt(i)) {
101            i++;
102        }
103        return i;
104    }
105
106    private void enlargeFilter(@NotNull final String filter) {
107        // "abcd" -> "abc"
108    }
109
110    private void narrowFilter(@NotNull final String filter) {
111        // "abc" -> "abcd"
112    }
113
114    /**
115     * @noinspection TypeMayBeWeakened
116     */
117    @NotNull
118    public Archetype<G, A, R> getNearestMatch(@NotNull final String name) {
119        int pos = Collections.binarySearch(archList, name, new Comparator<Object>() {
120
121            @Override
122            public int compare(final Object o1, final Object o2) {
123                final String s1;
124                if (o1 instanceof Archetype) {
125                    s1 = ((Archetype<?, ?, ?>) o1).getArchetypeName();
126                } else {
127                    s1 = o1.toString();
128                }
129                final String s2;
130                if (o2 instanceof Archetype) {
131                    s2 = ((Archetype<?, ?, ?>) o2).getArchetypeName();
132                } else {
133                    s2 = o2.toString();
134                }
135                return s1.compareToIgnoreCase(s2);
136            }
137        });
138        if (pos < 0) {
139            pos = -(pos + 1);
140        }
141        if (pos >= archList.size()) {
142            pos = archList.size() - 1;
143        }
144        if (pos < 0) {
145            pos = 0;
146        }
147        return archList.get(pos);
148    }
149
150}