]> gitweb.fperrin.net Git - Dictionary.git/blob - src/com/hughes/android/dictionary/engine/RowBase.java
2e094a46a108102d5cd1f899496487eafce5baa1
[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) throws IOException {
45     super(thisRowIndex);
46     this.index = index;
47     this.referenceIndex = raf.readInt();  // what this points to.
48   }
49
50   public RowBase(final int referenceIndex, final int thisRowIndex, final Index index) {
51     super(thisRowIndex);
52     this.index = index;
53     this.referenceIndex = referenceIndex;
54   }
55   
56   static final class RowKey {
57     final Class<? extends RowBase> rowClass;
58     final int referenceIndex;
59     
60     private RowKey(Class<? extends RowBase> rowClass, int referenceIndex) {
61       this.rowClass = rowClass;
62       this.referenceIndex = referenceIndex;
63     }
64     
65     @Override
66     public boolean equals(Object o) {
67       if (!(o instanceof RowKey)) {
68         return false;
69       }
70       final RowKey that = (RowKey) o;
71       return this.referenceIndex == that.referenceIndex && this.rowClass.equals(that.rowClass);
72     }
73     
74     @Override
75     public int hashCode() {
76       return rowClass.hashCode() + referenceIndex;
77     }
78   }
79   
80   public RowKey getRowKey() {
81     return new RowKey(this.getClass(), referenceIndex);
82   }
83
84   /**
85    * @return the TokenRow that this row is "filed under".
86    */
87   public TokenRow getTokenRow(final boolean search) {
88     if (tokenRow == null && search) {
89       int r = index() - 1;
90       int rUp = index() + 1;
91       while (r >= 0) {
92         final RowBase row = index.rows.get(r);
93         final TokenRow candidate = row.getTokenRow(false);
94         if (candidate != null) {
95           for (++r; r <= index(); ++r) {
96             index.rows.get(r).setTokenRow(candidate);
97           }
98           break;
99         }
100         if (rUp < index.rows.size()) {
101           final RowBase rowUp = index.rows.get(rUp);
102           TokenRow candidateUp = rowUp.getTokenRow(false);
103           if (candidateUp != null) {
104             // Did we hit the next set of TokenRows?
105             if (candidateUp.index() > this.index()) {  
106               final int tokenIndex = index.sortedIndexEntries.get(candidateUp.referenceIndex - 1).startRow;
107               candidateUp = (TokenRow) index.rows.get(tokenIndex);
108             }
109             for (--rUp; rUp >= index(); --rUp) {
110               index.rows.get(rUp).setTokenRow(candidateUp);
111             }
112             break;
113           }
114           rUp++;
115         }
116         --r;
117       }
118       assert tokenRow != null;
119     }
120     return tokenRow;
121   }
122   
123   public void setTokenRow(TokenRow tokenRow) {
124     assert this.tokenRow == null;
125     assert tokenRow != null;
126     this.tokenRow = tokenRow;
127   }
128
129   public abstract void print(PrintStream out);
130
131   public abstract String getRawText(final boolean compact);
132   
133   public abstract RowMatchType matches(final List<String> searchTokens, final Pattern orderedMatch, final Transliterator normalizer, boolean swapPairEntries);
134
135   // RowBase must manage "disk-based" polymorphism.  All other polymorphism is
136   // dealt with in the normal manner.
137   static class Serializer implements RAFListSerializer<RowBase> {
138     
139     final Index index;
140     
141     Serializer(final Index index) {
142       this.index = index;
143     }
144
145     @Override
146     public RowBase read(RandomAccessFile raf, final int listIndex) throws IOException {
147       final byte rowType = raf.readByte();
148       if (rowType == 0) {
149         return new PairEntry.Row(raf, listIndex, index);
150       } else if (rowType == 1 || rowType == 3) {
151         return new TokenRow(raf, listIndex, index, /* hasMainEntry */ rowType == 1);
152       } else if (rowType == 2) {
153         return new TextEntry.Row(raf, listIndex, index);
154       } else if (rowType == 4) {
155         return new HtmlEntry.Row(raf, listIndex, index);
156       }
157       throw new RuntimeException("Invalid rowType:" + rowType);
158     }
159
160     @Override
161     public void write(RandomAccessFile raf, RowBase t) throws IOException {
162       if (t instanceof PairEntry.Row) {
163         raf.writeByte(0);
164       } else if (t instanceof TokenRow) {
165         final TokenRow tokenRow = (TokenRow) t;
166         raf.writeByte(tokenRow.hasMainEntry ? 1 : 3);
167       } else if (t instanceof TextEntry.Row) {
168         raf.writeByte(2);
169       } else if (t instanceof HtmlEntry.Row) {
170         raf.writeByte(4);
171       }
172       raf.writeInt(t.referenceIndex);
173     }
174   }
175   
176   public static final class LengthComparator implements Comparator<RowBase> {
177     
178     final boolean swapPairEntries;
179
180     public LengthComparator(boolean swapPairEntries) {
181       this.swapPairEntries = swapPairEntries;
182     }
183
184     @Override
185     public int compare(RowBase row1, RowBase row2) {
186       final int l1 = row1.getSideLength(swapPairEntries);
187       final int l2 = row2.getSideLength(swapPairEntries);
188       return l1 < l2 ? -1 : l1 == l2 ? 0 : 1;
189     }
190   }
191
192   public int getSideLength(boolean swapPairEntries) {
193     return getRawText(false).length();
194   }
195   
196 }