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