OSDN Git Service

Fix non-latin character search problem & remove minimum word length options.
[neighbornote/NeighborNote.git] / src / cx / fbn / nevernote / sql / REnSearch.java
1 /*\r
2  * This file is part of NeverNote \r
3  * Copyright 2009 Randy Baumgarte\r
4  * \r
5  * This file may be licensed under the terms of of the\r
6  * GNU General Public License Version 2 (the ``GPL'').\r
7  *\r
8  * Software distributed under the License is distributed\r
9  * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
10  * express or implied. See the GPL for the specific language\r
11  * governing rights and limitations.\r
12  *\r
13  * You should have received a copy of the GPL along with this\r
14  * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
15  * or write to the Free Software Foundation, Inc.,\r
16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
17  *\r
18 */\r
19 \r
20 \r
21 package cx.fbn.nevernote.sql;\r
22 \r
23 import java.text.SimpleDateFormat;\r
24 import java.util.ArrayList;\r
25 import java.util.Calendar;\r
26 import java.util.GregorianCalendar;\r
27 import java.util.List;\r
28 import java.util.regex.Pattern;\r
29 \r
30 import org.apache.commons.lang.StringEscapeUtils;\r
31 \r
32 import com.evernote.edam.type.Note;\r
33 import com.evernote.edam.type.Notebook;\r
34 import com.evernote.edam.type.Tag;\r
35 \r
36 import cx.fbn.nevernote.sql.driver.NSqlQuery;\r
37 import cx.fbn.nevernote.utilities.ApplicationLogger;\r
38 \r
39 public class REnSearch {\r
40         \r
41         private final List<String>      searchWords;\r
42         private final List<String>  searchPhrases;\r
43         private final List<String>      notebooks;\r
44         private final List<String>      tags;\r
45         private final List<String>      intitle;\r
46         private final List<String>      created;\r
47         private final List<String>      updated;\r
48         private final List<String>      resource;\r
49         private final List<String>      subjectDate;\r
50         private final List<String>      longitude;\r
51         private final List<String>      latitude;\r
52         private final List<String>      altitude;\r
53         private final List<String>      author;\r
54         private final List<String>      source;\r
55         private final List<String>      sourceApplication;\r
56         private final List<String>      recoType;\r
57         private final List<String>      todo;\r
58         private final List<Tag>         tagIndex;\r
59         private final ApplicationLogger logger;\r
60 //      private final DatabaseConnection db;\r
61         private boolean any;\r
62         private int minimumRecognitionWeight = 80;\r
63         private final DatabaseConnection conn;\r
64         \r
65         public REnSearch(DatabaseConnection c, ApplicationLogger l, String s, List<Tag> t, int r) {\r
66                 logger = l;\r
67                 conn = c;\r
68                 tagIndex = t;\r
69                 minimumRecognitionWeight = r;\r
70                 searchWords = new ArrayList<String>();\r
71                 searchPhrases = new ArrayList<String>();\r
72                 notebooks = new ArrayList<String>();\r
73                 tags = new ArrayList<String>();\r
74                 intitle = new ArrayList<String>();\r
75                 created = new  ArrayList<String>();\r
76                 updated = new ArrayList<String>();\r
77                 resource = new ArrayList<String>();\r
78                 subjectDate = new ArrayList<String>();\r
79                 longitude = new ArrayList<String>();\r
80                 latitude = new ArrayList<String>();\r
81                 altitude = new ArrayList<String>();\r
82                 author = new ArrayList<String>();\r
83                 source = new ArrayList<String>();\r
84                 sourceApplication = new ArrayList<String>();\r
85                 recoType = new ArrayList<String>();\r
86                 todo = new ArrayList<String>();\r
87                 any = false;\r
88                 \r
89                 if (s == null) \r
90                         return;\r
91                 if (s.trim().equals(""))\r
92                         return;\r
93                 \r
94                 resolveSearch(s);\r
95         }\r
96                 \r
97         public List<String> getWords() { return searchWords; }\r
98         public List<String> getNotebooks() { return notebooks; }\r
99         public List<String> getIntitle() {      return intitle; }\r
100         public List<String> getTags() { return tags; }\r
101         public List<String> getResource() {     return resource; }\r
102         public List<String> getAuthor() { return author; }      \r
103         public List<String> getSource() { return source; }      \r
104         public List<String> getSourceApplication() { return sourceApplication; }        \r
105         public List<String> getRecoType() {     return recoType; }      \r
106         public List<String> getToDo() { return todo; }\r
107         public List<String> getLongitude() { return longitude; }\r
108         public List<String> getLatitude() { return latitude; }\r
109         public List<String> getAltitude() { return altitude; }\r
110         public List<String> getCreated() { return created; }\r
111         public List<String> getUpdated() { return updated; }\r
112         public List<String> getSubjectDate() { return subjectDate; }\r
113         \r
114 \r
115         // match tag names\r
116         private boolean matchTagsAll(List<String> tagNames) {\r
117                 List<String> list = getTags();\r
118                                 \r
119                 for (int j=0; j<list.size(); j++) {\r
120                         boolean negative = false;\r
121                         negative = false;\r
122                         if (list.get(j).startsWith("-"))\r
123                                 negative = true;\r
124                         int pos = list.get(j).indexOf(":");\r
125                         String filterName = cleanupWord(list.get(j).substring(pos+1));\r
126                         filterName = filterName.replace("*", ".*");   // setup for regular expression pattern match\r
127                         \r
128                         if (tagNames.size() == 0 && !negative)\r
129                                 return false;\r
130                         if (tagNames.size() == 0 && negative)\r
131                                 return true;\r
132                         \r
133                         boolean good = false;\r
134                         for (int i=0; i<tagNames.size() && !good; i++) {                \r
135                                 boolean matches = Pattern.matches(filterName.toLowerCase(),tagNames.get(i).toLowerCase());\r
136                                 if (matches && !negative)\r
137                                         good = true;\r
138                                 if (!matches && negative)\r
139                                         good = true;\r
140                         }\r
141                         if (!good)\r
142                                 return false;\r
143                 }\r
144                 return true;\r
145         }\r
146         \r
147         // match tag names\r
148         private boolean matchTagsAny(List<String> tagNames) {\r
149                 List<String> list = getTags();\r
150                 if (list.size() == 0)\r
151                         return true;\r
152                 \r
153                 boolean negative = false;               \r
154                 boolean found = false;\r
155                 \r
156                 for (int j=0; j<list.size(); j++) {\r
157                         negative = false;\r
158                         if (list.get(j).startsWith("-"))\r
159                                 negative = true;\r
160                         int pos = list.get(j).indexOf(":");\r
161                         String filterName = cleanupWord(list.get(j).substring(pos+1));\r
162                         filterName = filterName.replace("*", ".*");   // setup for regular expression pattern match\r
163                         \r
164                         if (tagNames.size() == 0)\r
165                                 found = false;\r
166 \r
167                         for (int i=0; i<tagNames.size(); i++) {         \r
168                                 boolean matches = Pattern.matches(filterName.toLowerCase(),tagNames.get(i).toLowerCase());\r
169                                 if (matches)\r
170                                         found = true;\r
171                         }\r
172                 }\r
173                 if (negative)\r
174                         return !found;\r
175                 else\r
176                         return found;\r
177         }\r
178         \r
179         // Match notebooks in search terms against notes\r
180         private boolean matchNotebook(String guid) {\r
181                 if (getNotebooks().size() == 0)\r
182                         return true;\r
183                 NotebookTable bookTable = new NotebookTable(logger, conn);\r
184                 List<Notebook> books = bookTable.getAll();\r
185 \r
186                 String name = new String("");\r
187                 for (int i=0; i<books.size(); i++) {\r
188                         if (guid.equalsIgnoreCase(books.get(i).getGuid())) {\r
189                                 name = books.get(i).getName();\r
190                                 i=books.size();\r
191                         }\r
192                 }\r
193                 if (any)\r
194                         return matchListAny(getNotebooks(), name);\r
195                 else\r
196                         return matchListAll(getNotebooks(), name);\r
197         }\r
198         // Match notebooks in search terms against notes\r
199         private boolean matchListAny(List<String> list, String title) {\r
200                 if (list.size() == 0)\r
201                         return true;\r
202                 boolean negative = false;\r
203                 boolean found = false;\r
204                 for (int i=0; i<list.size(); i++) {\r
205                         int pos = list.get(i).indexOf(":");\r
206                         negative = false;\r
207                         if (list.get(i).startsWith("-"))\r
208                                 negative = true;\r
209                         String filterName = cleanupWord(list.get(i).substring(pos+1));\r
210                         filterName = filterName.replace("*", ".*");   // setup for regular expression pattern match\r
211                         boolean matches = Pattern.matches(filterName.toLowerCase(),title.toLowerCase());\r
212                         if (matches)\r
213                                 found = true;\r
214                 }\r
215                 if (negative)\r
216                         return !found;\r
217                 else\r
218                         return found;\r
219         }\r
220         // Match notebooks in search terms against notes\r
221         private boolean matchContentAny(Note n) {\r
222                 if (todo.size() == 0 && resource.size() == 0 && searchPhrases.size() == 0)\r
223                         return true;\r
224 \r
225                 // pull back the record\r
226                 n = conn.getNoteTable().getNote(n.getGuid(), true, true, false, false, false);\r
227 \r
228                 // Check for search phrases\r
229                 String text = StringEscapeUtils.unescapeHtml(n.getContent().replaceAll("\\<.*?\\>", "")).toLowerCase();\r
230                 boolean negative = false;\r
231                 for (int i=0; i<searchPhrases.size(); i++) {\r
232                         String phrase = searchPhrases.get(i);\r
233                         if (phrase.startsWith("-")) {\r
234                                 negative = true;\r
235                                 phrase = phrase.substring(1);\r
236                         } else\r
237                                 negative = false;\r
238                         phrase = phrase.substring(1);\r
239                         phrase = phrase.substring(0,phrase.length()-1);\r
240                         if (text.indexOf(phrase)>=0) {\r
241                                 if (negative)\r
242                                         return false;\r
243                                 else\r
244                                         return true;\r
245                         }\r
246                         if (text.indexOf(phrase)<0 && negative)\r
247                                 return true;\r
248                 }\r
249                 \r
250                 for (int i=0; i<todo.size(); i++) {\r
251                         String value = todo.get(i);\r
252                         value = value.replace("\"", "");\r
253                         boolean desiredState;\r
254                         if (!value.endsWith(":false") && !value.endsWith(":true") && !value.endsWith(":*") && !value.endsWith("*"))\r
255                                 return false;\r
256                         if (value.endsWith(":false"))\r
257                                 desiredState = false;\r
258                         else\r
259                                 desiredState = true;\r
260                         if (value.startsWith("-"))\r
261                                 desiredState = !desiredState;\r
262                         int pos = n.getContent().indexOf("<en-todo");\r
263                         if (pos == -1 && value.startsWith("-") && (value.endsWith("*") || value.endsWith(":")))\r
264                                 return true;\r
265                         if (value.endsWith("*"))\r
266                                 return true;\r
267                         while (pos > -1) {\r
268                                 int endPos = n.getContent().indexOf("/>", pos);\r
269                                 String segment = n.getContent().substring(pos, endPos);\r
270                                 boolean currentState;\r
271                                 if (segment.toLowerCase().indexOf("checked=\"true\"") == -1)\r
272                                         currentState = false;\r
273                                 else\r
274                                         currentState = true;\r
275                                 if (desiredState == currentState)\r
276                                         return true;\r
277                                 \r
278                                 pos = n.getContent().indexOf("<en-todo", pos+1);\r
279                         }\r
280                 }\r
281                 \r
282                 // Check resources\r
283                 for (int i=0; i<resource.size(); i++) {\r
284                         String resourceString = resource.get(i);\r
285                         resourceString = resourceString.replace("\"", "");\r
286                         if (resourceString.startsWith("-"))\r
287                                 negative = true;\r
288                         resourceString = resourceString.substring(resourceString.indexOf(":")+1);\r
289                         for (int j=0; j<n.getResourcesSize(); j++) {\r
290                                 boolean match = stringMatch(n.getResources().get(j).getMime(), resourceString, negative);\r
291                                 if (match)\r
292                                         return true;\r
293                         }\r
294                 }\r
295                 return false;\r
296         }\r
297         \r
298         \r
299         // Take the initial search & split it apart\r
300         private void resolveSearch(String search) {\r
301                 List<String> words = new ArrayList<String>();\r
302                 StringBuffer b = new StringBuffer(search);\r
303                 \r
304                 int len = search.length();\r
305                 char nextChar = ' ';\r
306                 boolean quote = false;\r
307                 for (int i=0; i<len; i++) {\r
308                         if (search.charAt(i)==nextChar && !quote) {\r
309                                 b.setCharAt(i,'\0');\r
310                                 nextChar = ' ';\r
311                         } else {\r
312                                 if (search.charAt(i)=='\"') {\r
313                                         if (!quote) {\r
314                                                 quote=true;\r
315                                         } else {\r
316                                                 quote=false;\r
317                                         }\r
318                                 }\r
319                         }\r
320                         if (((i+2)<len) && search.charAt(i) == '\\') {\r
321                                 i=i+2;\r
322                         }\r
323                 }\r
324                 \r
325                 search = b.toString();\r
326                 int pos = 0;\r
327                 for (int i=0; i<search.length(); i++) {\r
328                         if (search.charAt(i) == '\0') {\r
329                                 search = search.substring(1);\r
330                                 i=0;\r
331                         } else {\r
332                                 pos = search.indexOf('\0');\r
333                                 if (pos > 0) {\r
334                                         words.add(search.substring(0,pos).toLowerCase());\r
335                                         search = search.substring(pos);\r
336                                         i=0;\r
337                                 }\r
338                         }\r
339                 }\r
340                 if (search.charAt(0)=='\0')     \r
341                         words.add(search.substring(1).toLowerCase());\r
342                 else\r
343                         words.add(search.toLowerCase());\r
344                 parseTerms(words);\r
345         }\r
346 \r
347         \r
348         // Parse out individual words into separate lists\r
349         // Supported options\r
350         // Tags\r
351         // Notebooks\r
352         // Intitle\r
353         // author\r
354         // source\r
355         // source application\r
356         // created\r
357         // updated\r
358         // subject date\r
359 \r
360         private void parseTerms(List<String> words) {\r
361                 \r
362                 for (int i=0; i<words.size(); i++) {\r
363                         String word = words.get(i);\r
364                         int pos = word.indexOf(":");\r
365                         if (word.startsWith("any:")) {\r
366                                 any = true;\r
367                                 word = word.substring(4).trim();\r
368                                 pos = word.indexOf(":");\r
369                         }\r
370                         boolean searchPhrase = false;\r
371                         if (pos < 0 && word.indexOf(" ") > 0) {\r
372                                 searchPhrase=true;\r
373                                 searchPhrases.add(word.toLowerCase());\r
374                         }\r
375                         if (!searchPhrase && pos < 0) \r
376                                 getWords().add("*"+word+"*");\r
377                         if (word.startsWith("intitle:")) \r
378                                 intitle.add("*"+word+"*");\r
379                         if (word.startsWith("-intitle:")) \r
380                                 intitle.add("*"+word+"*");\r
381                         if (word.startsWith("notebook:")) \r
382                                 notebooks.add(word);\r
383                         if (word.startsWith("-notebook:")) \r
384                                 notebooks.add(word);\r
385                         if (word.startsWith("tag:")) \r
386                                 tags.add(word);\r
387                         if (word.startsWith("-tag:")) \r
388                                 tags.add(word);\r
389                         if (word.startsWith("resource:")) \r
390                                 resource.add(word);\r
391                         if (word.startsWith("-resource:")) \r
392                                 resource.add(word);\r
393                         if (word.startsWith("author:")) \r
394                                 author.add(word);\r
395                         if (word.startsWith("-author:")) \r
396                                 author.add(word);\r
397                         if (word.startsWith("source:")) \r
398                                 source.add(word);\r
399                         if (word.startsWith("-source:")) \r
400                                 source.add(word);\r
401                         if (word.startsWith("sourceapplication:")) \r
402                                 sourceApplication.add(word);\r
403                         if (word.startsWith("-sourceapplication:")) \r
404                                 sourceApplication.add(word);\r
405                         if (word.startsWith("recotype:")) \r
406                                 recoType.add(word);\r
407                         if (word.startsWith("-recotype:")) \r
408                                 recoType.add(word);\r
409                         if (word.startsWith("todo:")) \r
410                                 todo.add(word);\r
411                         if (word.startsWith("-todo:")) \r
412                                 todo.add(word);\r
413 \r
414                         if (word.startsWith("latitude:")) \r
415                                 latitude.add(word);\r
416                         if (word.startsWith("-latitude:")) \r
417                                 latitude.add(word);\r
418                         if (word.startsWith("longitude:")) \r
419                                 longitude.add(word);\r
420                         if (word.startsWith("-longitude:")) \r
421                                 longitude.add(word);\r
422                         if (word.startsWith("altitude:")) \r
423                                 altitude.add(word);\r
424                         if (word.startsWith("-altitude:")) \r
425                                 altitude.add(word);\r
426 \r
427                         if (word.startsWith("created:")) \r
428                                 created.add(word);\r
429                         if (word.startsWith("-created:")) \r
430                                 created.add(word);\r
431                         if (word.startsWith("updated:")) \r
432                                 updated.add(word);\r
433                         if (word.startsWith("-updated:")) \r
434                                 updated.add(word);\r
435                         if (word.startsWith("subjectdate:")) \r
436                                 created.add(word);\r
437                         if (word.startsWith("-subjectdate:")) \r
438                                 created.add(word);\r
439 \r
440                 }\r
441         }\r
442         // Match notebooks in search terms against notes\r
443         private boolean matchListAll(List<String> list, String title) {\r
444                 if (list.size() == 0)\r
445                         return true;\r
446                 boolean negative = false;\r
447                 for (int i=0; i<list.size(); i++) {\r
448                         int pos = list.get(i).indexOf(":");\r
449                         negative = false;\r
450                         if (list.get(i).startsWith("-"))\r
451                                 negative = true;\r
452                         String filterName = cleanupWord(list.get(i).substring(pos+1));\r
453                         filterName = filterName.replace("*", ".*");   // setup for regular expression pattern match\r
454                         boolean matches = Pattern.matches(filterName.toLowerCase(),title.toLowerCase());\r
455                         if (matches && negative)\r
456                                 return false;\r
457                         if (matches && !negative)\r
458                                 return true;\r
459                 }\r
460                 if (negative)\r
461                         return true;\r
462                 else\r
463                         return false;\r
464         }\r
465         // Match notebooks in search terms against notes\r
466         private boolean matchContentAll(Note n) {\r
467                 if (todo.size() == 0 && resource.size() == 0 && searchPhrases.size() == 0)\r
468                         return true;\r
469                 \r
470                 boolean returnTodo = false;\r
471                 boolean returnResource = false;\r
472                 boolean returnPhrase = false;\r
473                 \r
474                 if (todo.size() == 0)\r
475                         returnTodo = true;\r
476                 if (resource.size() == 0)\r
477                         returnResource = true;\r
478                 if (searchPhrases.size() == 0)\r
479                         returnPhrase = true;\r
480                 \r
481                 \r
482                 n = conn.getNoteTable().getNote(n.getGuid(), true, true, false, false, false);\r
483                 \r
484                 // Check for search phrases\r
485                 String text = StringEscapeUtils.unescapeHtml(n.getContent().replaceAll("\\<.*?\\>", "")).toLowerCase();\r
486                 boolean negative = false;\r
487                 for (int i=0; i<searchPhrases.size(); i++) {\r
488                         String phrase = searchPhrases.get(i);\r
489                         if (phrase.startsWith("-")) {\r
490                                 negative = true;\r
491                                 phrase = phrase.substring(1);\r
492                         } else\r
493                                 negative = false;\r
494                         phrase = phrase.substring(1);\r
495                         phrase = phrase.substring(0,phrase.length()-1);\r
496                         if (text.indexOf(phrase)>=0) {\r
497                                 if (!negative)\r
498                                         returnPhrase = true;\r
499                         }\r
500                         if (text.indexOf(phrase)<0 && negative)\r
501                                 returnPhrase = true;\r
502                 }\r
503 \r
504                 \r
505                 for (int i=0; i<todo.size(); i++) {\r
506                         String value = todo.get(i);\r
507                         value = value.replace("\"", "");\r
508                         boolean desiredState;\r
509                         if (!value.endsWith(":false") && !value.endsWith(":true") && !value.endsWith(":*") && !value.endsWith("*"))\r
510                                 return false;\r
511                         if (value.endsWith(":false"))\r
512                                 desiredState = false;\r
513                         else\r
514                                 desiredState = true;\r
515                         if (value.startsWith("-"))\r
516                                 desiredState = !desiredState;\r
517                         int pos = n.getContent().indexOf("<en-todo");\r
518                         if (pos == -1 && value.startsWith("-") && (value.endsWith("*") || value.endsWith(":")))\r
519                                 return true;\r
520                         if (pos > -1 && value.startsWith("-") && (value.endsWith("*") || value.endsWith(":")))\r
521                                 return false;\r
522                         if (pos == -1) \r
523                                 return false;\r
524                         if (value.endsWith("*"))\r
525                                 returnTodo = true;\r
526                         while (pos > -1) {\r
527                                 int endPos = n.getContent().indexOf("/>", pos);\r
528                                 String segment = n.getContent().substring(pos, endPos);\r
529                                 boolean currentState;\r
530                                 if (segment.toLowerCase().indexOf("checked=\"true\"") == -1)\r
531                                         currentState = false;\r
532                                 else\r
533                                         currentState = true;\r
534                                 if (desiredState == currentState)\r
535                                         returnTodo = true;\r
536                                 \r
537                                 pos = n.getContent().indexOf("<en-todo", pos+1);\r
538                         }\r
539                 }\r
540                 \r
541                 // Check resources\r
542                 for (int i=0; i<resource.size(); i++) {\r
543                         String resourceString = resource.get(i);\r
544                         resourceString = resourceString.replace("\"", "");\r
545                         negative = false;\r
546                         if (resourceString.startsWith("-"))\r
547                                 negative = true;\r
548                         resourceString = resourceString.substring(resourceString.indexOf(":")+1);\r
549                         if (resourceString.equals(""))\r
550                                 return false;\r
551                         for (int j=0; j<n.getResourcesSize(); j++) {\r
552                                 boolean match = stringMatch(n.getResources().get(j).getMime(), resourceString, negative);\r
553                                 if (!match)\r
554                                         return false;\r
555                                 returnResource = true;\r
556                         }\r
557                 }\r
558                 \r
559                 return returnResource && returnTodo && returnPhrase;\r
560         }\r
561         \r
562         private boolean stringMatch(String content, String text, boolean negative) {\r
563                 String regex;\r
564                 if (content == null && !negative)\r
565                         return false;\r
566                 if (content == null && negative)\r
567                         return true;\r
568                 \r
569                 if (text.endsWith("*")) {\r
570                         text = text.substring(0,text.length()-1);\r
571                         regex = text;\r
572                 } else {\r
573                         regex = text;\r
574                 }\r
575                 content = content.toLowerCase();\r
576                 regex = regex.toLowerCase();\r
577                 boolean matches = content.startsWith(regex);\r
578                 if (negative)\r
579                         return !matches;\r
580                 return matches;\r
581         }\r
582         \r
583         // Remove odd strings from search terms\r
584         private String cleanupWord(String word) {\r
585                 if (word.startsWith("\""))\r
586                         word = word.substring(1);\r
587                 if (word.endsWith("\""))\r
588             word = word.substring(0,word.length()-1);\r
589                 word = word.replace("\\\"","\"");\r
590                 word = word.replace("\\\\","\\");\r
591                 \r
592                 return word;\r
593         }\r
594 \r
595         \r
596         // Match dates\r
597         private boolean matchDatesAll(List<String> dates, long noteDate) {\r
598                 if (dates.size()== 0) \r
599                         return true;\r
600                 \r
601                 boolean negative = false;\r
602                 for (int i=0; i<dates.size(); i++) {\r
603                         String requiredDate = dates.get(i);\r
604                         if (requiredDate.startsWith("-"))\r
605                                 negative = true;\r
606                         \r
607                         int response = 0;\r
608                         requiredDate = requiredDate.substring(requiredDate.indexOf(":")+1);\r
609                         try {\r
610                                 response = dateCheck(requiredDate, noteDate);\r
611                         } catch (java.lang.NumberFormatException e) {return false;}  {\r
612                                 if (negative && response < 0)\r
613                                         return false;\r
614                                 if (!negative && response > 0)\r
615                                         return false;\r
616                         }\r
617                 }\r
618                 return true;\r
619         }\r
620         private boolean matchDatesAny(List<String> dates, long noteDate) {\r
621                 if (dates.size()== 0) \r
622                         return true;\r
623                 \r
624                 boolean negative = false;\r
625                 for (int i=0; i<dates.size(); i++) {\r
626                         String requiredDate = dates.get(i);\r
627                         if (requiredDate.startsWith("-"))\r
628                                 negative = true;\r
629                         \r
630                         int response = 0;\r
631                         requiredDate = requiredDate.substring(requiredDate.indexOf(":")+1);\r
632                         try {\r
633                                 response = dateCheck(requiredDate, noteDate);\r
634                         } catch (java.lang.NumberFormatException e) {return false;}  {\r
635                                 if (negative && response > 0)\r
636                                         return true;\r
637                                 if (!negative && response < 0)\r
638                                         return true;\r
639                         }\r
640                 }\r
641                 return false;\r
642         }\r
643         \r
644         @SuppressWarnings("unused")\r
645         private void printCalendar(Calendar calendar) {\r
646                 // define output format and print\r
647                 SimpleDateFormat sdf = new SimpleDateFormat("d MMM yyyy hh:mm:ss aaa");\r
648                 String date = sdf.format(calendar.getTime());\r
649                 System.err.print(date);\r
650                 calendar = new GregorianCalendar();\r
651         }\r
652         \r
653         \r
654         //****************************************\r
655         //****************************************\r
656         // Match search terms against notes\r
657         //****************************************\r
658         //****************************************\r
659         public List<Note> matchWords() {\r
660                 logger.log(logger.EXTREME, "Inside EnSearch.matchWords()");\r
661                 \r
662                 StringBuffer buffer = new StringBuffer(100);\r
663                 Integer counter = 0;\r
664                 boolean subSelect = false;\r
665                 \r
666                 buffer.append("Select guid from Note ");\r
667                 if (searchWords.size() > 0) \r
668                         subSelect = true;\r
669                 if (subSelect) {\r
670                         buffer.append(" where guid in ");\r
671                 \r
672                         // Build the query words\r
673                         String connector;\r
674                         if (any)\r
675                                 connector = new String("or");\r
676                         else\r
677                                 connector = new String("and");\r
678                         for (int i=0; i<getWords().size(); i++) {\r
679                                 buffer.append("(Select distinct guid from words where ");\r
680                                 buffer.append("weight >= :weight"+counter.toString() +" and ");\r
681                                 if (getWords().get(i).indexOf("*")==-1)\r
682                                         buffer.append("word=:word" +counter.toString());\r
683                                 else\r
684                                         buffer.append("word like :word" +counter.toString());\r
685                                 counter++;\r
686                                 buffer.append(") ");\r
687                                 if (i < getWords().size() -1)\r
688                                         buffer.append(" " +connector +" guid in ");\r
689                         }\r
690                 }\r
691                 \r
692                 NSqlQuery query = new NSqlQuery(conn.getConnection());\r
693                 \r
694                 if (!query.prepare(buffer.toString()))\r
695                         logger.log(logger.HIGH, "EnSearch Sql Prepare Failed:" +query.lastError());\r
696                 \r
697                 if (subSelect) {\r
698                         // Do the binding\r
699                         Integer binder = 0;\r
700                         for (int i=0; i<getWords().size(); i++) {\r
701                                 String val = getWords().get(i);\r
702                                 val = val.replace('*', '%');\r
703                                 query.bindValue(":weight"+binder.toString(), minimumRecognitionWeight);\r
704                                 query.bindValue(":word"+binder.toString(), cleanupWord(val));\r
705                                 binder++;\r
706                         }       \r
707                 }\r
708 \r
709                 List<Note> guids = new ArrayList<Note>();\r
710                 NoteTable noteTable = new NoteTable(logger, conn);  \r
711                 if (!query.exec()) \r
712                         logger.log(logger.EXTREME, "EnSearch.matchWords query failed: " +query.lastError());\r
713                 List<String> validGuids = new ArrayList<String>();\r
714                 while (query.next()) {\r
715                         String guid = query.valueString(0);\r
716                         validGuids.add(guid);\r
717                 }\r
718 \r
719                 List<Note> noteIndex = noteTable.getAllNotes();\r
720                 for (int i=0; i<noteIndex.size(); i++) {\r
721                         Note n = noteIndex.get(i);\r
722                         boolean good = true;\r
723                         \r
724                         if (!validGuids.contains(n.getGuid()))\r
725                                 good = false;\r
726                                                 \r
727                         // Start matching special stuff, like tags & notebooks\r
728                         if (any) {\r
729                                 if (good && !matchTagsAny(n.getTagNames()))\r
730                                         good = false;\r
731                                 if (good && !matchNotebook(n.getNotebookGuid()))\r
732                                         good = false;\r
733                                 if (good && !matchListAny(getIntitle(), n.getTitle()))\r
734                                         good = false;\r
735                                 if (good && !matchListAny(getAuthor(), n.getAttributes().getAuthor()))\r
736                                         good = false;\r
737                                 if (good && !matchListAny(getSource(), n.getAttributes().getSource()))\r
738                                         good = false;\r
739                                 if (good && !matchListAny(getSourceApplication(), n.getAttributes().getSourceApplication()))\r
740                                         good = false;\r
741                                 if (good && !matchContentAny(n))\r
742                                         good = false;\r
743                                 if (good && !matchDatesAny(getCreated(), n.getCreated()))\r
744                                         good = false;\r
745                                 if (good && !matchDatesAny(getUpdated(), n.getUpdated()))\r
746                                         good = false;\r
747                                 if (good && n.getAttributes() != null && !matchDatesAny(getSubjectDate(), n.getAttributes().getSubjectDate()))\r
748                                         good = false;\r
749                         } else {\r
750                                 if (good && !matchTagsAll(n.getTagNames()))\r
751                                         good = false;\r
752                                 if (good && !matchNotebook(n.getNotebookGuid()))\r
753                                         good = false;\r
754                                 if (good && !matchListAll(getIntitle(), n.getTitle()))\r
755                                         good = false;\r
756                                 if (good && !matchListAll(getAuthor(), n.getAttributes().getAuthor()))\r
757                                         good = false;\r
758                                 if (good && !matchListAll(getSource(), n.getAttributes().getSource()))\r
759                                         good = false;\r
760                                 if (good && !matchListAll(getSourceApplication(), n.getAttributes().getSourceApplication()))\r
761                                         good = false;\r
762                                 if (good && !matchContentAll(n))\r
763                                         good = false;\r
764                                 if (good && !matchDatesAll(getCreated(), n.getCreated()))\r
765                                         good = false;\r
766                                 if (good && !matchDatesAll(getUpdated(), n.getUpdated()))\r
767                                         good = false;\r
768                                 if (good && n.getAttributes() != null && !matchDatesAll(getSubjectDate(), n.getAttributes().getSubjectDate()))\r
769                                         good = false;\r
770                         }\r
771                         if (good) {\r
772                                 guids.add(n);\r
773                         }\r
774                 }\r
775                 \r
776                 // For performance reasons, we didn't get the tags for every note individually.  We now need to \r
777                 // get them\r
778                 List<NoteTagsRecord> noteTags = noteTable.noteTagsTable.getAllNoteTags();\r
779                 for (int i=0; i<guids.size(); i++) {\r
780                         List<String> tags = new ArrayList<String>();\r
781                         List<String> names = new ArrayList<String>();\r
782                         for (int j=0; j<noteTags.size(); j++) {\r
783                                 if (guids.get(i).getGuid().equals(noteTags.get(j).noteGuid)) {\r
784                                         tags.add(noteTags.get(j).tagGuid);\r
785                                         names.add(getTagNameByGuid(noteTags.get(j).tagGuid));\r
786                                 }\r
787                         }\r
788                         \r
789                         guids.get(i).setTagGuids(tags);\r
790                         guids.get(i).setTagNames(names);\r
791                 };\r
792                 logger.log(logger.EXTREME, "Leaving EnSearch.matchWords()");\r
793                 return guids;\r
794         }\r
795         \r
796         \r
797         \r
798         private String getTagNameByGuid(String guid) {\r
799                 for (int i=0; i<tagIndex.size(); i++) {\r
800                         if (tagIndex.get(i).getGuid().equals(guid)) \r
801                                         return tagIndex.get(i).getName();\r
802                 }               \r
803                 return "";\r
804         }\r
805 \r
806         // Compare dates\r
807         public int dateCheck(String date, long noteDate)  throws java.lang.NumberFormatException  {\r
808                 int offset = 0;\r
809                 boolean found = false;\r
810                 GregorianCalendar calendar = new GregorianCalendar();\r
811                 \r
812                 if (date.contains("-")) {\r
813                         String modifier = date.substring(date.indexOf("-")+1);\r
814                         offset = new Integer(modifier);\r
815                         offset = 0-offset;\r
816                         date = date.substring(0,date.indexOf("-"));\r
817                 }\r
818                 \r
819                 if (date.contains("+")) {\r
820                         String modifier = date.substring(date.indexOf("+")+1);\r
821                         offset = new Integer(modifier);\r
822                         date = date.substring(0,date.indexOf("+"));\r
823                 }\r
824                 \r
825                 if (date.equalsIgnoreCase("today")) {\r
826                         calendar.add(Calendar.DATE, offset);\r
827                         calendar.set(Calendar.HOUR, 0);\r
828                         calendar.set(Calendar.MINUTE, 0);\r
829                         calendar.set(Calendar.SECOND, 1);\r
830                         found = true;\r
831                 }\r
832                 \r
833                 if (date.equalsIgnoreCase("month")) {\r
834                         calendar.add(Calendar.MONTH, offset);\r
835                         calendar.set(Calendar.DAY_OF_MONTH, 1);\r
836                         calendar.set(Calendar.HOUR, 0);\r
837                         calendar.set(Calendar.MINUTE, 0);\r
838                         calendar.set(Calendar.SECOND, 1);\r
839                         found = true;\r
840                 }\r
841 \r
842                 if (date.equalsIgnoreCase("year")) {\r
843                         calendar.add(Calendar.YEAR, offset);\r
844                         calendar.set(Calendar.MONTH, Calendar.JANUARY);\r
845                         calendar.set(Calendar.DAY_OF_MONTH, 1);\r
846                         calendar.set(Calendar.HOUR, 0);\r
847                         calendar.set(Calendar.MINUTE, 0);\r
848                         calendar.set(Calendar.SECOND, 1);\r
849                         found = true;\r
850                 }\r
851 \r
852                 if (date.equalsIgnoreCase("week")) {\r
853                         calendar.add(Calendar.DATE, 0-calendar.get(Calendar.DAY_OF_WEEK)+1);\r
854                         calendar.add(Calendar.DATE,(offset*7));\r
855                         calendar.set(Calendar.HOUR, 0);\r
856                         calendar.set(Calendar.MINUTE, 0);\r
857                         calendar.set(Calendar.SECOND, 1);\r
858 \r
859                         found = true;\r
860                 }\r
861                 \r
862                 // If nothing was found, then we have a date number\r
863                 if (!found) {\r
864                         calendar = stringToGregorianCalendar(date);\r
865                 }\r
866                 \r
867                 \r
868                 String dateTimeFormat = new String("yyyyMMdd-HHmmss");\r
869                 SimpleDateFormat simple = new SimpleDateFormat(dateTimeFormat);\r
870                 StringBuilder creationDate = new StringBuilder(simple.format(noteDate));\r
871                 GregorianCalendar nCalendar = stringToGregorianCalendar(creationDate.toString().replace("-", "T"));\r
872                 if (calendar == null || nCalendar == null)  // If we have something invalid, it automatically fails\r
873                         return 1;\r
874                 return calendar.compareTo(nCalendar);\r
875         }\r
876         private GregorianCalendar stringToGregorianCalendar(String date) {\r
877                 String datePart = date;\r
878                 GregorianCalendar calendar = new GregorianCalendar();\r
879                 boolean GMT = false;\r
880                 String timePart = "";\r
881                 if (date.contains("T")) {\r
882                         datePart = date.substring(0,date.indexOf("T"));\r
883                         timePart = date.substring(date.indexOf("T")+1);\r
884                 } else {\r
885                         timePart = "000001";\r
886                 }\r
887                 if (datePart.length() != 8)\r
888                         return null;\r
889                 calendar.set(Calendar.YEAR, new Integer(datePart.substring(0,4)));\r
890                 calendar.set(Calendar.MONTH, new Integer(datePart.substring(4,6))-1);\r
891                 calendar.set(Calendar.DAY_OF_MONTH, new Integer(datePart.substring(6)));\r
892                 if (timePart.endsWith("Z")) {\r
893                         GMT = true;\r
894                         timePart = timePart.substring(0,timePart.length()-1);\r
895                 }\r
896                 timePart = timePart.concat("000000");\r
897                 timePart = timePart.substring(0,6);\r
898                 calendar.set(Calendar.HOUR, new Integer(timePart.substring(0,2)));\r
899                 calendar.set(Calendar.MINUTE, new Integer(timePart.substring(2,4)));\r
900                 calendar.set(Calendar.SECOND, new Integer(timePart.substring(4)));\r
901                 if (GMT)\r
902                         calendar.set(Calendar.ZONE_OFFSET, -1*(calendar.get(Calendar.ZONE_OFFSET)/(1000*60*60)));\r
903                 return calendar;\r
904 \r
905         }\r
906                 \r
907 }\r