]> gitweb.fperrin.net Git - Dictionary.git/blob - src/com/hughes/android/dictionary/engine/HtmlEntry.java
Move Android code out of engine code.
[Dictionary.git] / src / com / hughes / android / dictionary / engine / HtmlEntry.java
1
2 package com.hughes.android.dictionary.engine;
3
4 import com.hughes.android.dictionary.C;
5 import com.hughes.util.StringUtil;
6 import com.hughes.util.raf.RAFListSerializer;
7 import com.hughes.util.raf.RAFSerializable;
8 import com.ibm.icu.text.Transliterator;
9
10 import java.io.IOException;
11 import java.io.PrintStream;
12 import java.io.RandomAccessFile;
13 import java.lang.ref.SoftReference;
14 import java.util.List;
15 import java.util.regex.Pattern;
16
17 public class HtmlEntry extends AbstractEntry implements RAFSerializable<HtmlEntry>,
18         Comparable<HtmlEntry> {
19
20     // Title is not HTML escaped.
21     public final String title;
22     public final LazyHtmlLoader lazyHtmlLoader;
23     public String html;
24
25     public HtmlEntry(final EntrySource entrySource, String title) {
26         super(entrySource);
27         this.title = title;
28         lazyHtmlLoader = null;
29     }
30
31     public HtmlEntry(Dictionary dictionary, RandomAccessFile raf, final int index)
32             throws IOException {
33         super(dictionary, raf, index);
34         title = raf.readUTF();
35         lazyHtmlLoader = new LazyHtmlLoader(raf);
36         html = null;
37     }
38
39     @Override
40     public void write(RandomAccessFile raf) throws IOException {
41         super.write(raf);
42         raf.writeUTF(title);
43
44         final byte[] bytes = getHtml().getBytes("UTF-8");
45         final byte[] zipBytes = StringUtil.zipBytes(bytes);
46         raf.writeInt(bytes.length);
47         raf.writeInt(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(RandomAccessFile raf, final int index) throws IOException {
77             return new HtmlEntry(dictionary, raf, index);
78         }
79
80         @Override
81         public void write(RandomAccessFile 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 RandomAccessFile raf, final int thisRowIndex,
110                 final Index index) throws IOException {
111             super(raf, thisRowIndex, index);
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 RandomAccessFile raf) throws IOException {
191             this.raf = raf;
192             numBytes = raf.readInt();
193             numZipBytes = raf.readInt();
194             offset = raf.getFilePointer();
195             raf.skipBytes(numZipBytes);
196         }
197
198         public String getHtml() {
199             String html = htmlRef.get();
200             if (html != null) {
201                 return html;
202             }
203             System.out.println("Loading Html: numBytes=" + numBytes + ", numZipBytes="
204                     + numZipBytes);
205             final byte[] bytes = new byte[numBytes];
206             final byte[] zipBytes = new byte[numZipBytes];
207             synchronized (raf) {
208                 try {
209                     raf.seek(offset);
210                     raf.read(zipBytes);
211                 } catch (IOException e) {
212                     throw new RuntimeException(e);
213                 }
214             }
215             try {
216                 StringUtil.unzipFully(zipBytes, bytes);
217                 html = new String(bytes, "UTF-8");
218             } catch (IOException e) {
219                 throw new RuntimeException(e);
220             }
221             htmlRef = new SoftReference<String>(html);
222             return html;
223         }
224     }
225
226 }