/*
* Priki - Prevalent Wiki
* Copyright (c) 2005 Priki
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* http://www.gnu.org/copyleft/gpl.html
*
* @author Giovane Roslindo Kuhn - grkuhn at gmail dot com
*
*/
package org.priki.utils;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import org.priki.bo.Wiki;
import org.priki.bo.Wikiword;
/**
* Class used to index a {@link Collection} of {@link Wikiwords},
* that supports case insensitive keywords.<br>
* This class holds a case sensitive {@link StringMap} of {@link Wikiwords},
* used in the default {@link Map} methods.<br>
* This class also holds a case insensitive {@link TreeMap},
* used to accelerate the {@link WikiwordIndex#startingWith(String)} searches.<br>
*
* TODO Synchronize modification operations from the StringMap.iterator() with the insensitive map<br>
*
* @author Giovane.Kuhn
* @since 13/02/2007
*/
public final class WikiwordIndex extends StringMap<Wikiword> {
private static final long serialVersionUID = 1L;
/**
* Index wikiwords by their lower case keyword.<br>
* Key: A case insensitive {@link String}<br>
* Value: {@link Map} of {@link Wikiwords} from the {@link Wiki}<br>
* TODO May be this could be transient
*/
private TreeMap<String, Map<String, Wikiword>> insensitiveMap;
private TreeMap<String, Map<String, Wikiword>> insensitiveMap() {
if (insensitiveMap == null) {
insensitiveMap = new TreeMap<String, Map<String, Wikiword>>();
}
return insensitiveMap;
}
/**
* Returns a {@link Collection} of {@link Wikiword} equals to the
* informed {@link key} ignoring the case sensitive.<br>
* @param key Key whose associated values is to be returned.
* @return {@link Collection} of {@link Wikiword} equals to
* the informed key ignoring case sensitive.<br>
* If any value match the informed key, returns an empty collection.
*/
public Collection<Wikiword> getIgnoreCase(String key) {
Map<String, Wikiword> ret = insensitiveMap().get(key.toLowerCase());
if (ret == null) {
return Collections.emptyList();
}
return new ArrayList<Wikiword>(ret.values());
}
@Override
public Collection<Wikiword> startingWith(String key) {
// Define the range of search (lower case)
String from = key.toLowerCase();
String to = from.substring(0, from.length() - 1) + (char) (from.charAt(from.length() - 1) + 1);
// Analyze each entry
List<Wikiword> ret = new ArrayList<Wikiword>();
for (Map<String, Wikiword> innerMap : insensitiveMap().subMap(from, to).values()) {
for (Wikiword wikiword : innerMap.values()) {
// Case insensitive wikiwods is ensured by the lower case map
if (!wikiword.isCaseSensitive()) {
ret.add(wikiword);
continue;
}
// Test case sensitivies wikiwords against informed key
if (wikiword.getKeyword().startsWith(key)) {
ret.add(wikiword);
}
}
}
return ret;
}
@Override
public Wikiword put(String key, Wikiword value) {
// Add to the insensitive map
String lowerKey = key.toLowerCase();
Map<String, Wikiword> innerMap = insensitiveMap().get(lowerKey);
if (innerMap == null) {
innerMap = new HashMap<String, Wikiword>();
insensitiveMap.put(lowerKey, innerMap);
}
innerMap.put(key, value);
// Add to the default map
return super.put(key, value);
}
@Override
public void putAll(Map< ? extends String, ? extends Wikiword> map) {
// Add to the insensitive map, the method put add to the default map
for (Map.Entry< ? extends String, ? extends Wikiword> entry : map.entrySet()) {
this.put(entry.getKey(), entry.getValue());
}
}
@Override
public Wikiword remove(Object key) {
// Remove from the insensitive map
String lowerKey = ((String) key).toLowerCase();
Map<String, Wikiword> innerMap = insensitiveMap().get(lowerKey);
if (innerMap != null) {
innerMap.remove(key);
// Check if inner map is empty
if (innerMap.isEmpty()) {
insensitiveMap.remove(lowerKey);
}
}
// Remove from the default map
return super.remove(key);
}
@Override
public void clear() {
insensitiveMap().clear();
super.clear();
}
@Override
public Object clone() {
WikiwordIndex ret = (WikiwordIndex) super.clone();
ret.insensitiveMap = new TreeMap<String, Map<String, Wikiword>>();
ret.insensitiveMap.putAll(insensitiveMap());
return ret;
}
}