001/*
002 * Copyright 2010-2015 Institut Pasteur.
003 * 
004 * This file is part of Icy.
005 * 
006 * Icy is free software: you can redistribute it and/or modify
007 * it under the terms of the GNU General Public License as published by
008 * the Free Software Foundation, either version 3 of the License, or
009 * (at your option) any later version.
010 * 
011 * Icy is distributed in the hope that it will be useful,
012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
014 * GNU General Public License for more details.
015 * 
016 * You should have received a copy of the GNU General Public License
017 * along with Icy. If not, see <http://www.gnu.org/licenses/>.
018 */
019package plugins.kernel.searchprovider;
020
021import icy.plugin.PluginDescriptor;
022import icy.util.StringUtil;
023
024import java.util.ArrayList;
025import java.util.List;
026
027/**
028 * @author Stephane
029 */
030public class PluginSearchResultProducerHelper
031{
032    public static class SearchWord
033    {
034        public final String word;
035        public final boolean mandatory;
036        public final boolean reject;
037
038        public SearchWord(String word)
039        {
040            super();
041
042            if (word.startsWith("+"))
043            {
044                mandatory = true;
045                reject = false;
046                if (word.length() > 1)
047                    this.word = word.substring(1);
048                else
049                    this.word = "";
050            }
051            else if (word.startsWith("+"))
052            {
053                mandatory = false;
054                reject = true;
055                if (word.length() > 1)
056                    this.word = word.substring(1);
057                else
058                    this.word = "";
059            }
060            else
061            {
062                mandatory = false;
063                reject = false;
064                this.word = word;
065            }
066        }
067
068        public boolean isEmpty()
069        {
070            return StringUtil.isEmpty(word);
071        }
072
073        public int length()
074        {
075            return word.length();
076        }
077    }
078
079    public static List<SearchWord> getSearchWords(String text)
080    {
081        final List<String> words = StringUtil.split(text);
082        final List<SearchWord> result = new ArrayList<SearchWord>();
083
084        for (String w : words)
085        {
086            final SearchWord sw = new SearchWord(w);
087            if (!sw.isEmpty())
088                result.add(sw);
089        }
090
091        return result;
092    }
093
094    public static boolean getShortSearch(List<SearchWord> words)
095    {
096        return (words.size() == 1) && (words.get(0).length() <= 2);
097    }
098
099    public static int searchInPlugin(PluginDescriptor plugin, List<SearchWord> words)
100    {
101        final boolean startWithOnly = PluginSearchResultProducerHelper.getShortSearch(words);
102        int result = 0;
103
104        // search for all word
105        for (SearchWord sw : words)
106        {
107            final int r = searchInPlugin(plugin, sw.word, startWithOnly);
108
109            // mandatory word not found ? --> reject
110            if ((r == 0) && sw.mandatory)
111                return 0;
112            // reject word found ? --> reject
113            else if ((r > 0) && sw.reject)
114                return 0;
115
116            result += r;
117        }
118
119        // return score
120        return result;
121    }
122
123    public static int searchInPlugin(PluginDescriptor plugin, String word, boolean startWithOnly)
124    {
125        if (plugin.getPluginClass() != null)
126        {
127            // we don't want abstract nor interface nor bundled plugin in results list
128            if (plugin.isAbstract() || plugin.isInterface())
129                return 0;
130            // we don't want bundled plugin which are not actionable
131            if (plugin.isBundled() && !plugin.isActionable())
132                return 0;
133        }
134
135        final String wordlc = word.toLowerCase();
136        final String name = plugin.getName().toLowerCase();
137        int ind;
138
139        ind = name.indexOf(wordlc);
140        if (ind >= 0)
141        {
142            // plugin name start with keyword --> highest priority result
143            if (ind == 0)
144                return 10;
145            // plugin name has a word starting by keyword --> high priority result
146            else if (name.charAt(ind - 1) == ' ')
147                return 9;
148            // don't allow partial match for short search
149            else if (startWithOnly)
150                return 0;
151            // name contains keyword --> high/medium priority result
152            else
153                return 8;
154        }
155
156        // more search...
157        if (!startWithOnly)
158        {
159            final String description = plugin.getDescription().toLowerCase();
160
161            ind = description.indexOf(wordlc);
162            if (ind >= 0)
163            {
164                // plugin description start with keyword --> medium
165                if (ind == 0)
166                    return 5;
167                // plugin description has a word starting by keyword --> medium/low priority result
168                else if (description.charAt(ind - 1) == ' ')
169                    return 4;
170                // description contains keyword --> lowest priority
171                else
172                    return 1;
173            }
174        }
175
176        // not found
177        return 0;
178    }
179}