]> gitweb.fperrin.net Git - Dictionary.git/blob - src/com/hughes/android/dictionary/Dictionary.java
c0a35880879a86649be99a2841f092f8f95e7be5
[Dictionary.git] / src / com / hughes / android / dictionary / Dictionary.java
1 package com.hughes.android.dictionary;\r
2 \r
3 import java.io.IOException;\r
4 import java.io.RandomAccessFile;\r
5 import java.util.ArrayList;\r
6 import java.util.List;\r
7 import java.util.concurrent.atomic.AtomicBoolean;\r
8 \r
9 import com.hughes.util.CachingList;\r
10 import com.hughes.util.raf.RAFList;\r
11 import com.hughes.util.raf.RAFFactory;\r
12 import com.hughes.util.raf.RAFSerializable;\r
13 import com.hughes.util.raf.RAFSerializableSerializer;\r
14 import com.hughes.util.raf.RAFSerializer;\r
15 import com.hughes.util.raf.UniformRAFList;\r
16 \r
17 public final class Dictionary implements RAFSerializable<Dictionary> {\r
18   \r
19   private static final String VERSION_CODE = "DictionaryVersion=2.0";\r
20 \r
21   static final RAFSerializer<SimpleEntry> ENTRY_SERIALIZER = null;\r
22   static final RAFSerializer<Row> ROW_SERIALIZER = new RAFSerializableSerializer<Row>(\r
23       Row.RAF_FACTORY);\r
24   static final RAFSerializer<IndexEntry> INDEX_ENTRY_SERIALIZER = new RAFSerializableSerializer<IndexEntry>(\r
25       IndexEntry.RAF_FACTORY);\r
26 \r
27   final String dictionaryInfo;\r
28   final List<String> sources;\r
29   final List<Entry> entries;\r
30   final LanguageData[] languageDatas = new LanguageData[2];\r
31 \r
32   public Dictionary(final String dictionaryInfo, final Language language0, final Language language1) {\r
33     this.dictionaryInfo = dictionaryInfo;\r
34     sources = new ArrayList<String>();\r
35     languageDatas[0] = new LanguageData(this, language0, SimpleEntry.LANG1);\r
36     languageDatas[1] = new LanguageData(this, language1, SimpleEntry.LANG2);\r
37     entries = new ArrayList<Entry>();\r
38   }\r
39 \r
40   public Dictionary(final RandomAccessFile raf) throws IOException {\r
41     dictionaryInfo = raf.readUTF();\r
42     sources = new ArrayList<String>(RAFList.create(raf, RAFSerializer.STRING, raf.getFilePointer()));\r
43     entries = null;\r
44     languageDatas[0] = new LanguageData(this, raf, SimpleEntry.LANG1);\r
45     languageDatas[1] = new LanguageData(this, raf, SimpleEntry.LANG2);\r
46     final String version = raf.readUTF();\r
47     if (!VERSION_CODE.equals(version)) {\r
48       throw new IOException("Invalid dictionary version, found " + version + ", expected: " + VERSION_CODE);\r
49     }\r
50   }\r
51 \r
52   public void write(RandomAccessFile raf) throws IOException {\r
53     raf.writeUTF(dictionaryInfo);\r
54     RAFList.write(raf, sources, RAFSerializer.STRING);\r
55     //RAFList.write(raf, entries, ENTRY_SERIALIZER);\r
56     languageDatas[0].write(raf);\r
57     languageDatas[1].write(raf);\r
58     raf.writeUTF(VERSION_CODE);\r
59   }\r
60 \r
61   final class LanguageData implements RAFSerializable<LanguageData> {\r
62     final Dictionary dictionary;\r
63     final Language language;\r
64     final byte lang;\r
65     final List<Row> rows;\r
66     final List<IndexEntry> sortedIndex;\r
67 \r
68     LanguageData(final Dictionary dictionary, final Language language, final byte lang) {\r
69       this.dictionary = dictionary;\r
70       this.language = language;\r
71       this.lang = lang;\r
72       rows = new ArrayList<Row>();\r
73       sortedIndex = new ArrayList<IndexEntry>();\r
74     }\r
75 \r
76     LanguageData(final Dictionary dictionary, final RandomAccessFile raf, final byte lang) throws IOException {\r
77       this.dictionary = dictionary;\r
78       language = Language.lookup(raf.readUTF());\r
79       if (language == null) {\r
80         throw new RuntimeException("Unknown language.");\r
81       }\r
82       this.lang = lang;\r
83       rows = CachingList.create(UniformRAFList.create(raf, ROW_SERIALIZER, raf\r
84           .getFilePointer()), 10000);\r
85       sortedIndex = CachingList.create(RAFList.create(raf,\r
86           INDEX_ENTRY_SERIALIZER, raf.getFilePointer()), 10000);\r
87     }\r
88 \r
89     public void write(final RandomAccessFile raf) throws IOException {\r
90       raf.writeUTF(language.symbol);\r
91       UniformRAFList.write(raf, rows, ROW_SERIALIZER, 4);\r
92       RAFList.write(raf, sortedIndex, INDEX_ENTRY_SERIALIZER);\r
93     }\r
94 \r
95     String rowToString(final Row row, final boolean onlyFirstSubentry) {\r
96       return null;\r
97       //return row.isToken() ? sortedIndex.get(row.getIndex()).word : entries\r
98       //    .get(row.getIndex()).getRawText(onlyFirstSubentry);\r
99     }\r
100 \r
101     int lookup(String word, final AtomicBoolean interrupted) {\r
102       word = word.toLowerCase();\r
103 \r
104       int start = 0;\r
105       int end = sortedIndex.size();\r
106       while (start < end) {\r
107         final int mid = (start + end) / 2;\r
108         if (interrupted.get()) {\r
109           return mid;\r
110         }\r
111         final IndexEntry midEntry = sortedIndex.get(mid);\r
112         if (midEntry.word.equals("pre-print")) {\r
113           System.out.println();\r
114         }\r
115 \r
116         final int comp = language.sortComparator.compare(word, midEntry.word.toLowerCase());\r
117         if (comp == 0) {\r
118           int result = mid;\r
119           while (result > 0 && language.findComparator.compare(word, sortedIndex.get(result - 1).word.toLowerCase()) == 0) {\r
120             --result;\r
121             if (interrupted.get()) {\r
122               return result;\r
123             }\r
124           }\r
125           return result;\r
126         } else if (comp < 0) {\r
127 //          Log.d("THAD", "Upper bound: " + midEntry);\r
128           end = mid;\r
129         } else {\r
130 //          Log.d("THAD", "Lower bound: " + midEntry);\r
131           start = mid + 1;\r
132         }\r
133       }\r
134       return Math.min(sortedIndex.size() - 1, start);\r
135     }\r
136     \r
137     public int getPrevTokenRow(final int rowIndex) {\r
138       final IndexEntry indexEntry = getIndexEntryForRow(rowIndex);\r
139       final Row tokenRow = rows.get(indexEntry.startRow);\r
140       assert tokenRow.isToken();\r
141       final int prevTokenIndex = tokenRow.getIndex() - 1;\r
142       if (indexEntry.startRow == rowIndex && prevTokenIndex >= 0) {\r
143         return sortedIndex.get(prevTokenIndex).startRow;\r
144       }\r
145       return indexEntry.startRow;\r
146     }\r
147 \r
148     public int getNextTokenRow(final int rowIndex) {\r
149       final IndexEntry indexEntry = getIndexEntryForRow(rowIndex);\r
150       final Row tokenRow = rows.get(indexEntry.startRow);\r
151       assert tokenRow.isToken();\r
152       final int nextTokenIndex = tokenRow.getIndex() + 1;\r
153       if (nextTokenIndex < sortedIndex.size()) {\r
154         return sortedIndex.get(nextTokenIndex).startRow;\r
155       }\r
156       return rows.size() - 1;\r
157     }\r
158 \r
159     public IndexEntry getIndexEntryForRow(final int rowIndex) {\r
160       // TODO: this kinda blows.\r
161       int r = rowIndex;\r
162       Row row;\r
163       while (true) {\r
164         row = rows.get(r); \r
165         if (row.isToken() || row.indexEntry != null) {\r
166           break;\r
167         }\r
168         --r;\r
169       }\r
170       final IndexEntry indexEntry = row.isToken() ? sortedIndex.get(row.getIndex()) : row.indexEntry;\r
171       for (; r <= rowIndex; ++r) {\r
172         rows.get(r).indexEntry = indexEntry;\r
173       }\r
174       assert rows.get(indexEntry.startRow).isToken();\r
175       return indexEntry;\r
176     }\r
177   }\r
178 \r
179   public static final class Row implements RAFSerializable<Row> {\r
180     final int index;\r
181 \r
182     IndexEntry indexEntry = null;\r
183 \r
184     public Row(final int index) {\r
185       this.index = index;\r
186     }\r
187 \r
188     static final RAFFactory<Row> RAF_FACTORY = new RAFFactory<Row>() {\r
189       public Row create(RandomAccessFile raf) throws IOException {\r
190         return new Row(raf.readInt());\r
191       }\r
192     };\r
193 \r
194     public void write(RandomAccessFile raf) throws IOException {\r
195       raf.writeInt(index);\r
196     }\r
197 \r
198     boolean isToken() {\r
199       return index < 0;\r
200     }\r
201 \r
202     public int getIndex() {\r
203       if (index >= 0) {\r
204         return index;\r
205       }\r
206       return -index - 1;\r
207     }\r
208   }\r
209 \r
210   public static final class IndexEntry implements RAFSerializable<IndexEntry> {\r
211     final String word;\r
212     final int startRow;\r
213 \r
214     public IndexEntry(final String word, final int startRow) {\r
215       this.word = word;\r
216       this.startRow = startRow;\r
217     }\r
218 \r
219     static final RAFFactory<IndexEntry> RAF_FACTORY = new RAFFactory<IndexEntry>() {\r
220       public IndexEntry create(RandomAccessFile raf) throws IOException {\r
221         final String word = raf.readUTF();\r
222         final int startRow = raf.readInt();\r
223         return new IndexEntry(word, startRow);\r
224       }\r
225     };\r
226 \r
227     public void write(final RandomAccessFile raf) throws IOException {\r
228       raf.writeUTF(word);\r
229       raf.writeInt(startRow);\r
230     }\r
231 \r
232     @Override\r
233     public String toString() {\r
234       return word + "@" + startRow;\r
235     }\r
236 \r
237   }\r
238 \r
239 }\r