]> gitweb.fperrin.net Git - Dictionary.git/blob - src/com/hughes/android/dictionary/engine/HtmlEntry.java
More compact row list format.
[Dictionary.git] / src / com / hughes / android / dictionary / engine / HtmlEntry.java
1
2 package com.hughes.android.dictionary.engine;
3
4 import com.hughes.util.StringUtil;
5 import com.hughes.util.raf.RAFListSerializer;
6 import com.hughes.util.raf.RAFSerializable;
7 import com.ibm.icu.text.Transliterator;
8
9 import java.io.DataInput;
10 import java.io.DataOutput;
11 import java.io.IOException;
12 import java.io.PrintStream;
13 import java.io.RandomAccessFile;
14 import java.lang.ref.SoftReference;
15 import java.util.List;
16 import java.util.regex.Pattern;
17
18 public class HtmlEntry extends AbstractEntry implements RAFSerializable<HtmlEntry>,
19         Comparable<HtmlEntry> {
20
21     // Title is not HTML escaped.
22     public final String title;
23     public final LazyHtmlLoader lazyHtmlLoader;
24     public String html;
25
26     public HtmlEntry(final EntrySource entrySource, String title) {
27         super(entrySource);
28         this.title = title;
29         lazyHtmlLoader = null;
30     }
31
32     public HtmlEntry(Dictionary dictionary, DataInput raf, final int index)
33             throws IOException {
34         super(dictionary, raf, index);
35         title = raf.readUTF();
36         lazyHtmlLoader = new LazyHtmlLoader(raf, dictionary.dictFileVersion);
37         html = null;
38     }
39
40     @Override
41     public void write(DataOutput raf) throws IOException {
42         super.write(raf);
43         raf.writeUTF(title);
44
45         final byte[] bytes = getHtml().getBytes("UTF-8");
46         final byte[] zipBytes = StringUtil.zipBytes(bytes);
47         StringUtil.writeVarInt(raf, zipBytes.length);
48         raf.write(zipBytes);
49     }
50
51     String getHtml() {
52         return html != null ? html : lazyHtmlLoader.getHtml();
53     }
54
55     @Override
56     public void addToDictionary(Dictionary dictionary) {
57         assert index == -1;
58         dictionary.htmlEntries.add(this);
59         index = dictionary.htmlEntries.size() - 1;
60     }
61
62     @Override
63     public RowBase CreateRow(int rowIndex, Index dictionaryIndex) {
64         return new Row(this.index, rowIndex, dictionaryIndex);
65     }
66
67     static final class Serializer implements RAFListSerializer<HtmlEntry> {
68
69         final Dictionary dictionary;
70
71         Serializer(Dictionary dictionary) {
72             this.dictionary = dictionary;
73         }
74
75         @Override
76         public HtmlEntry read(DataInput raf, final int index) throws IOException {
77             return new HtmlEntry(dictionary, raf, index);
78         }
79
80         @Override
81         public void write(DataOutput raf, HtmlEntry t) throws IOException {
82             t.write(raf);
83         }
84     }
85
86     public String getRawText(final boolean compact) {
87         return title + ":\n" + getHtml();
88     }
89
90     @Override
91     public int compareTo(HtmlEntry another) {
92         if (title.compareTo(another.title) != 0) {
93             return title.compareTo(another.title);
94         }
95         return getHtml().compareTo(another.getHtml());
96     }
97
98     @Override
99     public String toString() {
100         return getRawText(false);
101     }
102
103     // --------------------------------------------------------------------
104
105     public static class Row extends RowBase {
106
107         boolean isExpanded = false;
108
109         Row(final DataInput raf, final int thisRowIndex,
110                 final Index index, int extra) throws IOException {
111             super(raf, thisRowIndex, index, extra);
112         }
113
114         Row(final int referenceIndex, final int thisRowIndex,
115                 final Index index) {
116             super(referenceIndex, thisRowIndex, index);
117         }
118
119         @Override
120         public String toString() {
121             return getRawText(false);
122         }
123
124         public HtmlEntry getEntry() {
125             return index.dict.htmlEntries.get(referenceIndex);
126         }
127
128         @Override
129         public void print(PrintStream out) {
130             final HtmlEntry entry = getEntry();
131             out.println("See also HtmlEntry:" + entry.title);
132         }
133
134         @Override
135         public String getRawText(boolean compact) {
136             final HtmlEntry entry = getEntry();
137             return entry.getRawText(compact);
138         }
139
140         @Override
141         public RowMatchType matches(final List<String> searchTokens,
142                 final Pattern orderedMatchPattern, final Transliterator normalizer,
143                 final boolean swapPairEntries) {
144             final String text = normalizer.transform(getRawText(false));
145             if (orderedMatchPattern.matcher(text).find()) {
146                 return RowMatchType.ORDERED_MATCH;
147             }
148             for (int i = searchTokens.size() - 1; i >= 0; --i) {
149                 final String searchToken = searchTokens.get(i);
150                 if (!text.contains(searchToken)) {
151                     return RowMatchType.NO_MATCH;
152                 }
153             }
154             return RowMatchType.BAG_OF_WORDS_MATCH;
155         }
156     }
157
158     public static String htmlBody(final List<HtmlEntry> htmlEntries, final String indexShortName) {
159         final StringBuilder result = new StringBuilder();
160         for (final HtmlEntry htmlEntry : htmlEntries) {
161             final String titleEscaped = StringUtil.escapeUnicodeToPureHtml(htmlEntry.title);
162             result.append(String.format("<h1><a href=\"%s\">%s</a></h1>\n<p>%s\n",
163                     formatQuickdicUrl(indexShortName, htmlEntry.title), titleEscaped,
164                     htmlEntry.getHtml()));
165         }
166         return result.toString();
167     }
168
169     public static String formatQuickdicUrl(final String indexShortName, final String text) {
170         assert !indexShortName.contains(":");
171         assert text.length() > 0;
172         return String.format("q://d?%s&%s", indexShortName, StringUtil.encodeForUrl(text));
173     }
174
175     public static boolean isQuickdicUrl(String url) {
176         return url.startsWith("q://d?");
177     }
178
179     // --------------------------------------------------------------------
180
181     public static final class LazyHtmlLoader {
182         final RandomAccessFile raf;
183         final long offset;
184         final int numBytes;
185         final int numZipBytes;
186
187         // Not sure this volatile is right, but oh well.
188         volatile SoftReference<String> htmlRef = new SoftReference<String>(null);
189
190         private LazyHtmlLoader(final DataInput inp, int version) throws IOException {
191             raf = (RandomAccessFile)inp;
192             if (version >= 7) {
193                 numBytes = -1;
194                 numZipBytes = StringUtil.readVarInt(raf);
195             } else {
196                 numBytes = raf.readInt();
197                 numZipBytes = raf.readInt();
198             }
199             offset = raf.getFilePointer();
200             raf.skipBytes(numZipBytes);
201         }
202
203         public String getHtml() {
204             String html = htmlRef.get();
205             if (html != null) {
206                 return html;
207             }
208             System.out.println("Loading Html: numBytes=" + numBytes + ", numZipBytes="
209                     + numZipBytes);
210             final byte[] zipBytes = new byte[numZipBytes];
211             synchronized (raf) {
212                 try {
213                     raf.seek(offset);
214                     raf.read(zipBytes);
215                 } catch (IOException e) {
216                     throw new RuntimeException(e);
217                 }
218             }
219             try {
220                 final byte[] bytes = StringUtil.unzipFully(zipBytes, numBytes);
221                 html = new String(bytes, "UTF-8");
222             } catch (IOException e) {
223                 throw new RuntimeException(e);
224             }
225             htmlRef = new SoftReference<String>(html);
226             return html;
227         }
228     }
229
230 }