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