OSDN Git Service

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