//#condition !(TinyMode || TinyModeExport || LightMode || LightModeExport)
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package org.albite.dictionary;
import java.io.IOException;
import java.lang.ref.WeakReference;
import org.albite.albite.AlbiteMIDlet;
import org.albite.io.RandomReadingFile;
import org.albite.lang.AlbiteCharacter;
import org.albite.lang.TextTools;
/**
*
* @author albus
*/
public class Dictionary {
public static final String FILE_EXTENSION = ".ald";
public static final int MAGIC_NUMBER = 1095516740;
private static final String WORD_NOT_FOUND = "Word not found.";
/*
* This one had better be a odd value, so that the suggestions would be
* centered around a "best-find" word.
*/
private static final int NUMBER_OF_SUGGESTIONS = 21;
private final RandomReadingFile file;
private final int indexPosition;
private WeakReference indexEntries = null;
private String title;
private String language;
public Dictionary(final String filename)
throws DictionaryException {
try {
this.file = new RandomReadingFile(filename);
// } catch (IOException e) {
} catch (Exception e) {
throw new DictionaryException(e.toString());
}
try {
/*
* Check magic number
*/
if (file.readInt() != MAGIC_NUMBER) {
throw new DictionaryException();
}
/*
* Read header
*/
title = file.readUTF();
language = file.readUTF();
indexPosition = file.readInt();
} catch (Exception e) {
throw new DictionaryException("Dictionary is corrupted");
}
}
/**
* Loads the index
* @throws DictionaryException
*/
private DictEntries load() throws DictionaryException {
if (indexEntries != null) {
final DictEntries entries = (DictEntries) indexEntries.get();
if (entries != null) {
/*
* Dict already loaded.
*/
return entries;
}
}
try {
file.seek(indexPosition);
final int wordsCount = file.readInt();
final char[][] indexEntryNames = new char[wordsCount][];
final int[] indexEntryPositions = new int[wordsCount];
for (int i = 0; i < wordsCount; i++) {
indexEntryNames[i] = file.readUTFchars();
indexEntryPositions[i] = file.readInt();
}
DictEntries entries =
new DictEntries(indexEntryNames, indexEntryPositions);
indexEntries = new WeakReference(entries);
return entries;
} catch (Exception e) {
throw new DictionaryException("Cannot load dictionary index");
} catch (OutOfMemoryError e) {
throw new DictionaryException("Out of memory while loading index");
}
}
/**
* Unloads the index, thus freeing memory.
*/
public final void unload() {
indexEntries = null;
}
public final String[] lookUp(final String lookingFor)
throws DictionaryException {
final DictEntries de = load();
//#debug
AlbiteMIDlet.LOGGER.log("lowercasing");
final char[] text =
AlbiteCharacter.toLowerCase(lookingFor.toCharArray());
//#debug
AlbiteMIDlet.LOGGER.log("binary search");
int searchResult = TextTools.binarySearch(de.names, text);
if (searchResult >= 0) {
/*
* The word was found, so no suggestions neccessary.
*/
//#debug
AlbiteMIDlet.LOGGER.log("word found. getting definitions");
return new String[] {getDefinition(searchResult)};
}
/*
* We need to increment the found index by one
* as it has been decreased by one by the indexSearch method.
*/
searchResult = -searchResult + 1;
/*
* Returns a maximum of 11 suggestions.
*/
final int offset = NUMBER_OF_SUGGESTIONS / 2;
int left = searchResult - offset;
int right = searchResult + offset;
/*
* First check left side, if the "center" (i.e. searchResult)
* is too much in the left
*/
if (left < 0) {
left = 0;
right = NUMBER_OF_SUGGESTIONS;
}
/*
* Check if the "center" is too much in the right.
*/
if (right >= de.names.length) {
right = de.names.length - 1;
left = right - NUMBER_OF_SUGGESTIONS;
}
/*
* This might happen in the extreme case of a dictionary
* having less number of items than NUMBER_OF_SUGGESTIONS
* However, this might be quite possible for a simple
* in-book dictionary.
*/
if (left < 0) {
left = 0;
}
final int len = right - left + 1;
final String[] res = new String[len];
for (int i = 0; i < len; i++) {
res[i] = new String(de.names[left + i]);
}
//#debug
AlbiteMIDlet.LOGGER.log("returning suggestions");
return res;
}
public final String getDefinition(final String lookingFor)
throws DictionaryException {
final DictEntries de = load();
final char[] text = lookingFor.toCharArray();
final int searchResult = TextTools.binarySearch(de.names, text);
if (searchResult < 0) {
return WORD_NOT_FOUND;
}
return getDefinition(searchResult);
}
private String getDefinition(final int index)
throws DictionaryException {
final DictEntries de = load();
if (index < 0 || index > de.positions.length) {
return WORD_NOT_FOUND;
}
final int pos = de.positions[index];
try {
file.seek(pos);
final String s = file.readUTF();
return s;
} catch (Exception e) {
return WORD_NOT_FOUND;
}
}
private class DictEntries {
final char[][] names;
final int[] positions;
DictEntries(final char[][] names, final int[] positions) {
this.names = names;
this.positions = positions;
}
}
public final String getTitle() {
return title;
}
public final String getLanguage() {
return language;
}
public final void close() throws IOException {
file.close();
}
}