]> gitweb.fperrin.net Git - Dictionary.git/blob - src/com/hughes/android/dictionary/engine/RowBase.java
d76eb30bc6c6455a217280f62054a45c40a95cdb
[Dictionary.git] / src / com / hughes / android / dictionary / engine / RowBase.java
1 // Copyright 2011 Google Inc. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 package com.hughes.android.dictionary.engine;
16
17 import com.hughes.util.IndexedObject;
18 import com.hughes.util.raf.RAFListSerializer;
19 import com.ibm.icu.text.Transliterator;
20
21 import java.io.IOException;
22 import java.io.PrintStream;
23 import java.io.RandomAccessFile;
24 import java.util.Comparator;
25 import java.util.List;
26 import java.util.regex.Pattern;
27
28 public abstract class RowBase extends IndexedObject {
29     /**
30      * the Index owning this RowBase.
31      */
32     public final Index index;
33
34     /**
35      * Where this RowBase points to.
36      */
37     public final int referenceIndex;
38
39     /**
40      * the TokenRow above this RowBase, populated on demand.
41      */
42     private TokenRow tokenRow = null;
43
44     RowBase(final RandomAccessFile raf, final int thisRowIndex, final Index index)
45             throws IOException {
46         super(thisRowIndex);
47         this.index = index;
48         this.referenceIndex = raf.readInt(); // what this points to.
49     }
50
51     public RowBase(final int referenceIndex, final int thisRowIndex, final Index index) {
52         super(thisRowIndex);
53         this.index = index;
54         this.referenceIndex = referenceIndex;
55     }
56
57     static final class RowKey {
58         final Class<? extends RowBase> rowClass;
59         final int referenceIndex;
60
61         private RowKey(Class<? extends RowBase> rowClass, int referenceIndex) {
62             this.rowClass = rowClass;
63             this.referenceIndex = referenceIndex;
64         }
65
66         @Override
67         public boolean equals(Object o) {
68             if (!(o instanceof RowKey)) {
69                 return false;
70             }
71             final RowKey that = (RowKey) o;
72             return this.referenceIndex == that.referenceIndex
73                     && this.rowClass.equals(that.rowClass);
74         }
75
76         @Override
77         public int hashCode() {
78             return rowClass.hashCode() + referenceIndex;
79         }
80     }
81
82     public RowKey getRowKey() {
83         return new RowKey(this.getClass(), referenceIndex);
84     }
85
86     /**
87      * @return the TokenRow that this row is "filed under".
88      */
89     public TokenRow getTokenRow(final boolean search) {
90         if (tokenRow == null && search) {
91             int r = index() - 1;
92             int rUp = index() + 1;
93             while (r >= 0) {
94                 final RowBase row = index.rows.get(r);
95                 final TokenRow candidate = row.getTokenRow(false);
96                 if (candidate != null) {
97                     for (++r; r <= index(); ++r) {
98                         index.rows.get(r).setTokenRow(candidate);
99                     }
100                     break;
101                 }
102                 if (rUp < index.rows.size()) {
103                     final RowBase rowUp = index.rows.get(rUp);
104                     TokenRow candidateUp = rowUp.getTokenRow(false);
105                     if (candidateUp != null) {
106                         // Did we hit the next set of TokenRows?
107                         if (candidateUp.index() > this.index()) {
108                             final int tokenIndex = index.sortedIndexEntries
109                                     .get(candidateUp.referenceIndex - 1).startRow;
110                             candidateUp = (TokenRow) index.rows.get(tokenIndex);
111                         }
112                         for (--rUp; rUp >= index(); --rUp) {
113                             index.rows.get(rUp).setTokenRow(candidateUp);
114                         }
115                         break;
116                     }
117                     rUp++;
118                 }
119                 --r;
120             }
121             assert tokenRow != null;
122         }
123         return tokenRow;
124     }
125
126     public void setTokenRow(TokenRow tokenRow) {
127         assert this.tokenRow == null;
128         assert tokenRow != null;
129         this.tokenRow = tokenRow;
130     }
131
132     public abstract void print(PrintStream out);
133
134     public abstract String getRawText(final boolean compact);
135
136     public abstract RowMatchType matches(final List<String> searchTokens,
137             final Pattern orderedMatch, final Transliterator normalizer, boolean swapPairEntries);
138
139     // RowBase must manage "disk-based" polymorphism. All other polymorphism is
140     // dealt with in the normal manner.
141     static class Serializer implements RAFListSerializer<RowBase> {
142
143         final Index index;
144
145         Serializer(final Index index) {
146             this.index = index;
147         }
148
149         @Override
150         public RowBase read(RandomAccessFile raf, final int listIndex) throws IOException {
151             final byte rowType = raf.readByte();
152             if (rowType == 0) {
153                 return new PairEntry.Row(raf, listIndex, index);
154             } else if (rowType == 1 || rowType == 3) {
155                 return new TokenRow(raf, listIndex, index, /* hasMainEntry */rowType == 1);
156             } else if (rowType == 2) {
157                 return new TextEntry.Row(raf, listIndex, index);
158             } else if (rowType == 4) {
159                 return new HtmlEntry.Row(raf, listIndex, index);
160             }
161             throw new RuntimeException("Invalid rowType:" + rowType);
162         }
163
164         @Override
165         public void write(RandomAccessFile raf, RowBase t) throws IOException {
166             if (t instanceof PairEntry.Row) {
167                 raf.writeByte(0);
168             } else if (t instanceof TokenRow) {
169                 final TokenRow tokenRow = (TokenRow) t;
170                 raf.writeByte(tokenRow.hasMainEntry ? 1 : 3);
171             } else if (t instanceof TextEntry.Row) {
172                 raf.writeByte(2);
173             } else if (t instanceof HtmlEntry.Row) {
174                 raf.writeByte(4);
175             }
176             raf.writeInt(t.referenceIndex);
177         }
178     }
179
180     public static final class LengthComparator implements Comparator<RowBase> {
181
182         final boolean swapPairEntries;
183
184         public LengthComparator(boolean swapPairEntries) {
185             this.swapPairEntries = swapPairEntries;
186         }
187
188         @Override
189         public int compare(RowBase row1, RowBase row2) {
190             final int l1 = row1.getSideLength(swapPairEntries);
191             final int l2 = row2.getSideLength(swapPairEntries);
192             return l1 < l2 ? -1 : l1 == l2 ? 0 : 1;
193         }
194     }
195
196     public int getSideLength(boolean swapPairEntries) {
197         return getRawText(false).length();
198     }
199
200 }