OSDN Git Service

b2b4e44dba8f14dc9bb88926f6a6fc968d046006
[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 //                              getWords().add("*"+word+"*");           //// WILDCARD\r
378                         if (word.startsWith("intitle:")) \r
379                                 intitle.add("*"+word+"*");\r
380                         if (word.startsWith("-intitle:")) \r
381                                 intitle.add("*"+word+"*");\r
382                         if (word.startsWith("notebook:")) \r
383                                 notebooks.add(word);\r
384                         if (word.startsWith("-notebook:")) \r
385                                 notebooks.add(word);\r
386                         if (word.startsWith("tag:")) \r
387                                 tags.add(word);\r
388                         if (word.startsWith("-tag:")) \r
389                                 tags.add(word);\r
390                         if (word.startsWith("resource:")) \r
391                                 resource.add(word);\r
392                         if (word.startsWith("-resource:")) \r
393                                 resource.add(word);\r
394                         if (word.startsWith("author:")) \r
395                                 author.add(word);\r
396                         if (word.startsWith("-author:")) \r
397                                 author.add(word);\r
398                         if (word.startsWith("source:")) \r
399                                 source.add(word);\r
400                         if (word.startsWith("-source:")) \r
401                                 source.add(word);\r
402                         if (word.startsWith("sourceapplication:")) \r
403                                 sourceApplication.add(word);\r
404                         if (word.startsWith("-sourceapplication:")) \r
405                                 sourceApplication.add(word);\r
406                         if (word.startsWith("recotype:")) \r
407                                 recoType.add(word);\r
408                         if (word.startsWith("-recotype:")) \r
409                                 recoType.add(word);\r
410                         if (word.startsWith("todo:")) \r
411                                 todo.add(word);\r
412                         if (word.startsWith("-todo:")) \r
413                                 todo.add(word);\r
414 \r
415                         if (word.startsWith("latitude:")) \r
416                                 latitude.add(word);\r
417                         if (word.startsWith("-latitude:")) \r
418                                 latitude.add(word);\r
419                         if (word.startsWith("longitude:")) \r
420                                 longitude.add(word);\r
421                         if (word.startsWith("-longitude:")) \r
422                                 longitude.add(word);\r
423                         if (word.startsWith("altitude:")) \r
424                                 altitude.add(word);\r
425                         if (word.startsWith("-altitude:")) \r
426                                 altitude.add(word);\r
427 \r
428                         if (word.startsWith("created:")) \r
429                                 created.add(word);\r
430                         if (word.startsWith("-created:")) \r
431                                 created.add(word);\r
432                         if (word.startsWith("updated:")) \r
433                                 updated.add(word);\r
434                         if (word.startsWith("-updated:")) \r
435                                 updated.add(word);\r
436                         if (word.startsWith("subjectdate:")) \r
437                                 created.add(word);\r
438                         if (word.startsWith("-subjectdate:")) \r
439                                 created.add(word);\r
440 \r
441                 }\r
442         }\r
443         // Match notebooks in search terms against notes\r
444         private boolean matchListAll(List<String> list, String title) {\r
445                 if (list.size() == 0)\r
446                         return true;\r
447                 boolean negative = false;\r
448                 for (int i=0; i<list.size(); i++) {\r
449                         int pos = list.get(i).indexOf(":");\r
450                         negative = false;\r
451                         if (list.get(i).startsWith("-"))\r
452                                 negative = true;\r
453                         String filterName = cleanupWord(list.get(i).substring(pos+1));\r
454                         filterName = filterName.replace("*", ".*");   // setup for regular expression pattern match\r
455                         boolean matches = Pattern.matches(filterName.toLowerCase(),title.toLowerCase());\r
456                         if (matches && negative)\r
457                                 return false;\r
458                         if (matches && !negative)\r
459                                 return true;\r
460                 }\r
461                 if (negative)\r
462                         return true;\r
463                 else\r
464                         return false;\r
465         }\r
466         // Match notebooks in search terms against notes\r
467         private boolean matchContentAll(Note n) {\r
468                 if (todo.size() == 0 && resource.size() == 0 && searchPhrases.size() == 0)\r
469                         return true;\r
470                 \r
471                 boolean returnTodo = false;\r
472                 boolean returnResource = false;\r
473                 boolean returnPhrase = false;\r
474                 \r
475                 if (todo.size() == 0)\r
476                         returnTodo = true;\r
477                 if (resource.size() == 0)\r
478                         returnResource = true;\r
479                 if (searchPhrases.size() == 0)\r
480                         returnPhrase = true;\r
481                 \r
482                 \r
483                 n = conn.getNoteTable().getNote(n.getGuid(), true, true, false, false, false);\r
484                 \r
485                 // Check for search phrases\r
486                 String text = StringEscapeUtils.unescapeHtml(n.getContent().replaceAll("\\<.*?\\>", "")).toLowerCase();\r
487                 boolean negative = false;\r
488                 for (int i=0; i<searchPhrases.size(); i++) {\r
489                         String phrase = searchPhrases.get(i);\r
490                         if (phrase.startsWith("-")) {\r
491                                 negative = true;\r
492                                 phrase = phrase.substring(1);\r
493                         } else\r
494                                 negative = false;\r
495                         phrase = phrase.substring(1);\r
496                         phrase = phrase.substring(0,phrase.length()-1);\r
497                         if (text.indexOf(phrase)>=0) {\r
498                                 if (!negative)\r
499                                         returnPhrase = true;\r
500                         }\r
501                         if (text.indexOf(phrase)<0 && negative)\r
502                                 returnPhrase = true;\r
503                 }\r
504 \r
505                 \r
506                 for (int i=0; i<todo.size(); i++) {\r
507                         String value = todo.get(i);\r
508                         value = value.replace("\"", "");\r
509                         boolean desiredState;\r
510                         if (!value.endsWith(":false") && !value.endsWith(":true") && !value.endsWith(":*") && !value.endsWith("*"))\r
511                                 return false;\r
512                         if (value.endsWith(":false"))\r
513                                 desiredState = false;\r
514                         else\r
515                                 desiredState = true;\r
516                         if (value.startsWith("-"))\r
517                                 desiredState = !desiredState;\r
518                         int pos = n.getContent().indexOf("<en-todo");\r
519                         if (pos == -1 && value.startsWith("-") && (value.endsWith("*") || value.endsWith(":")))\r
520                                 return true;\r
521                         if (pos > -1 && value.startsWith("-") && (value.endsWith("*") || value.endsWith(":")))\r
522                                 return false;\r
523                         if (pos == -1) \r
524                                 return false;\r
525                         if (value.endsWith("*"))\r
526                                 returnTodo = true;\r
527                         while (pos > -1) {\r
528                                 int endPos = n.getContent().indexOf("/>", pos);\r
529                                 String segment = n.getContent().substring(pos, endPos);\r
530                                 boolean currentState;\r
531                                 if (segment.toLowerCase().indexOf("checked=\"true\"") == -1)\r
532                                         currentState = false;\r
533                                 else\r
534                                         currentState = true;\r
535                                 if (desiredState == currentState)\r
536                                         returnTodo = true;\r
537                                 \r
538                                 pos = n.getContent().indexOf("<en-todo", pos+1);\r
539                         }\r
540                 }\r
541                 \r
542                 // Check resources\r
543                 for (int i=0; i<resource.size(); i++) {\r
544                         String resourceString = resource.get(i);\r
545                         resourceString = resourceString.replace("\"", "");\r
546                         negative = false;\r
547                         if (resourceString.startsWith("-"))\r
548                                 negative = true;\r
549                         resourceString = resourceString.substring(resourceString.indexOf(":")+1);\r
550                         if (resourceString.equals(""))\r
551                                 return false;\r
552                         for (int j=0; j<n.getResourcesSize(); j++) {\r
553                                 boolean match = stringMatch(n.getResources().get(j).getMime(), resourceString, negative);\r
554                                 if (!match)\r
555                                         return false;\r
556                                 returnResource = true;\r
557                         }\r
558                 }\r
559                 \r
560                 return returnResource && returnTodo && returnPhrase;\r
561         }\r
562         \r
563         private boolean stringMatch(String content, String text, boolean negative) {\r
564                 String regex;\r
565                 if (content == null && !negative)\r
566                         return false;\r
567                 if (content == null && negative)\r
568                         return true;\r
569                 \r
570                 if (text.endsWith("*")) {\r
571                         text = text.substring(0,text.length()-1);\r
572                         regex = text;\r
573                 } else {\r
574                         regex = text;\r
575                 }\r
576                 content = content.toLowerCase();\r
577                 regex = regex.toLowerCase();\r
578                 boolean matches = content.startsWith(regex);\r
579                 if (negative)\r
580                         return !matches;\r
581                 return matches;\r
582         }\r
583         \r
584         // Remove odd strings from search terms\r
585         private String cleanupWord(String word) {\r
586                 if (word.startsWith("\""))\r
587                         word = word.substring(1);\r
588                 if (word.endsWith("\""))\r
589             word = word.substring(0,word.length()-1);\r
590                 word = word.replace("\\\"","\"");\r
591                 word = word.replace("\\\\","\\");\r
592                 \r
593                 return word;\r
594         }\r
595 \r
596         \r
597         // Match dates\r
598         private boolean matchDatesAll(List<String> dates, long noteDate) {\r
599                 if (dates.size()== 0) \r
600                         return true;\r
601                 \r
602                 boolean negative = false;\r
603                 for (int i=0; i<dates.size(); i++) {\r
604                         String requiredDate = dates.get(i);\r
605                         if (requiredDate.startsWith("-"))\r
606                                 negative = true;\r
607                         \r
608                         int response = 0;\r
609                         requiredDate = requiredDate.substring(requiredDate.indexOf(":")+1);\r
610                         try {\r
611                                 response = dateCheck(requiredDate, noteDate);\r
612                         } catch (java.lang.NumberFormatException e) {return false;}  {\r
613                                 if (negative && response < 0)\r
614                                         return false;\r
615                                 if (!negative && response > 0)\r
616                                         return false;\r
617                         }\r
618                 }\r
619                 return true;\r
620         }\r
621         private boolean matchDatesAny(List<String> dates, long noteDate) {\r
622                 if (dates.size()== 0) \r
623                         return true;\r
624                 \r
625                 boolean negative = false;\r
626                 for (int i=0; i<dates.size(); i++) {\r
627                         String requiredDate = dates.get(i);\r
628                         if (requiredDate.startsWith("-"))\r
629                                 negative = true;\r
630                         \r
631                         int response = 0;\r
632                         requiredDate = requiredDate.substring(requiredDate.indexOf(":")+1);\r
633                         try {\r
634                                 response = dateCheck(requiredDate, noteDate);\r
635                         } catch (java.lang.NumberFormatException e) {return false;}  {\r
636                                 if (negative && response > 0)\r
637                                         return true;\r
638                                 if (!negative && response < 0)\r
639                                         return true;\r
640                         }\r
641                 }\r
642                 return false;\r
643         }\r
644         \r
645         @SuppressWarnings("unused")\r
646         private void printCalendar(Calendar calendar) {\r
647                 // define output format and print\r
648                 SimpleDateFormat sdf = new SimpleDateFormat("d MMM yyyy hh:mm:ss aaa");\r
649                 String date = sdf.format(calendar.getTime());\r
650                 System.err.print(date);\r
651                 calendar = new GregorianCalendar();\r
652         }\r
653         \r
654         \r
655         //****************************************\r
656         //****************************************\r
657         // Match search terms against notes\r
658         //****************************************\r
659         //****************************************\r
660         public List<Note> matchWords() {\r
661                 logger.log(logger.EXTREME, "Inside EnSearch.matchWords()");\r
662                 \r
663                 StringBuffer buffer = new StringBuffer(100);\r
664                 Integer counter = 0;\r
665                 boolean subSelect = false;\r
666                 \r
667                 buffer.append("Select guid from Note ");\r
668                 if (searchWords.size() > 0) \r
669                         subSelect = true;\r
670                 if (subSelect) {\r
671                         buffer.append(" where guid in ");\r
672                 \r
673                         // Build the query words\r
674                         String connector;\r
675                         if (any)\r
676                                 connector = new String("or");\r
677                         else\r
678                                 connector = new String("and");\r
679                         for (int i=0; i<getWords().size(); i++) {\r
680                                 buffer.append("(Select distinct guid from words where ");\r
681                                 buffer.append("weight >= :weight"+counter.toString() +" and ");\r
682                                 if (getWords().get(i).indexOf("*")==-1)\r
683                                         buffer.append("word=:word" +counter.toString());\r
684                                 else\r
685                                         buffer.append("word like :word" +counter.toString());\r
686                                 counter++;\r
687                                 buffer.append(") ");\r
688                                 if (i < getWords().size() -1)\r
689                                         buffer.append(" " +connector +" guid in ");\r
690                         }\r
691                 }\r
692                 \r
693                 NSqlQuery query = new NSqlQuery(conn.getConnection());\r
694                 \r
695                 if (!query.prepare(buffer.toString()))\r
696                         logger.log(logger.HIGH, "EnSearch Sql Prepare Failed:" +query.lastError());\r
697                 \r
698                 if (subSelect) {\r
699                         // Do the binding\r
700                         Integer binder = 0;\r
701                         for (int i=0; i<getWords().size(); i++) {\r
702                                 String val = getWords().get(i);\r
703                                 val = val.replace('*', '%');\r
704                                 query.bindValue(":weight"+binder.toString(), minimumRecognitionWeight);\r
705                                 query.bindValue(":word"+binder.toString(), cleanupWord(val));\r
706                                 binder++;\r
707                         }       \r
708                 }\r
709 \r
710                 List<Note> guids = new ArrayList<Note>();\r
711                 NoteTable noteTable = new NoteTable(logger, conn);  \r
712                 if (!query.exec()) \r
713                         logger.log(logger.EXTREME, "EnSearch.matchWords query failed: " +query.lastError());\r
714                 List<String> validGuids = new ArrayList<String>();\r
715                 while (query.next()) {\r
716                         String guid = query.valueString(0);\r
717                         validGuids.add(guid);\r
718                 }\r
719 \r
720                 List<Note> noteIndex = noteTable.getAllNotes();\r
721                 for (int i=0; i<noteIndex.size(); i++) {\r
722                         Note n = noteIndex.get(i);\r
723                         boolean good = true;\r
724                         \r
725                         if (!validGuids.contains(n.getGuid()))\r
726                                 good = false;\r
727                                                 \r
728                         // Start matching special stuff, like tags & notebooks\r
729                         if (any) {\r
730                                 if (good && !matchTagsAny(n.getTagNames()))\r
731                                         good = false;\r
732                                 if (good && !matchNotebook(n.getNotebookGuid()))\r
733                                         good = false;\r
734                                 if (good && !matchListAny(getIntitle(), n.getTitle()))\r
735                                         good = false;\r
736                                 if (good && !matchListAny(getAuthor(), n.getAttributes().getAuthor()))\r
737                                         good = false;\r
738                                 if (good && !matchListAny(getSource(), n.getAttributes().getSource()))\r
739                                         good = false;\r
740                                 if (good && !matchListAny(getSourceApplication(), n.getAttributes().getSourceApplication()))\r
741                                         good = false;\r
742                                 if (good && !matchContentAny(n))\r
743                                         good = false;\r
744                                 if (good && !matchDatesAny(getCreated(), n.getCreated()))\r
745                                         good = false;\r
746                                 if (good && !matchDatesAny(getUpdated(), n.getUpdated()))\r
747                                         good = false;\r
748                                 if (good && n.getAttributes() != null && !matchDatesAny(getSubjectDate(), n.getAttributes().getSubjectDate()))\r
749                                         good = false;\r
750                         } else {\r
751                                 if (good && !matchTagsAll(n.getTagNames()))\r
752                                         good = false;\r
753                                 if (good && !matchNotebook(n.getNotebookGuid()))\r
754                                         good = false;\r
755                                 if (good && !matchListAll(getIntitle(), n.getTitle()))\r
756                                         good = false;\r
757                                 if (good && !matchListAll(getAuthor(), n.getAttributes().getAuthor()))\r
758                                         good = false;\r
759                                 if (good && !matchListAll(getSource(), n.getAttributes().getSource()))\r
760                                         good = false;\r
761                                 if (good && !matchListAll(getSourceApplication(), n.getAttributes().getSourceApplication()))\r
762                                         good = false;\r
763                                 if (good && !matchContentAll(n))\r
764                                         good = false;\r
765                                 if (good && !matchDatesAll(getCreated(), n.getCreated()))\r
766                                         good = false;\r
767                                 if (good && !matchDatesAll(getUpdated(), n.getUpdated()))\r
768                                         good = false;\r
769                                 if (good && n.getAttributes() != null && !matchDatesAll(getSubjectDate(), n.getAttributes().getSubjectDate()))\r
770                                         good = false;\r
771                         }\r
772                         if (good) {\r
773                                 guids.add(n);\r
774                         }\r
775                 }\r
776                 \r
777                 // For performance reasons, we didn't get the tags for every note individually.  We now need to \r
778                 // get them\r
779                 List<NoteTagsRecord> noteTags = noteTable.noteTagsTable.getAllNoteTags();\r
780                 for (int i=0; i<guids.size(); i++) {\r
781                         List<String> tags = new ArrayList<String>();\r
782                         List<String> names = new ArrayList<String>();\r
783                         for (int j=0; j<noteTags.size(); j++) {\r
784                                 if (guids.get(i).getGuid().equals(noteTags.get(j).noteGuid)) {\r
785                                         tags.add(noteTags.get(j).tagGuid);\r
786                                         names.add(getTagNameByGuid(noteTags.get(j).tagGuid));\r
787                                 }\r
788                         }\r
789                         \r
790                         guids.get(i).setTagGuids(tags);\r
791                         guids.get(i).setTagNames(names);\r
792                 };\r
793                 logger.log(logger.EXTREME, "Leaving EnSearch.matchWords()");\r
794                 return guids;\r
795         }\r
796         \r
797         \r
798         \r
799         private String getTagNameByGuid(String guid) {\r
800                 for (int i=0; i<tagIndex.size(); i++) {\r
801                         if (tagIndex.get(i).getGuid().equals(guid)) \r
802                                         return tagIndex.get(i).getName();\r
803                 }               \r
804                 return "";\r
805         }\r
806 \r
807         // Compare dates\r
808         public int dateCheck(String date, long noteDate)  throws java.lang.NumberFormatException  {\r
809                 int offset = 0;\r
810                 boolean found = false;\r
811                 GregorianCalendar calendar = new GregorianCalendar();\r
812                 \r
813                 if (date.contains("-")) {\r
814                         String modifier = date.substring(date.indexOf("-")+1);\r
815                         offset = new Integer(modifier);\r
816                         offset = 0-offset;\r
817                         date = date.substring(0,date.indexOf("-"));\r
818                 }\r
819                 \r
820                 if (date.contains("+")) {\r
821                         String modifier = date.substring(date.indexOf("+")+1);\r
822                         offset = new Integer(modifier);\r
823                         date = date.substring(0,date.indexOf("+"));\r
824                 }\r
825                 \r
826                 if (date.equalsIgnoreCase("today")) {\r
827                         calendar.add(Calendar.DATE, offset);\r
828                         calendar.set(Calendar.HOUR, 0);\r
829                         calendar.set(Calendar.MINUTE, 0);\r
830                         calendar.set(Calendar.SECOND, 1);\r
831                         found = true;\r
832                 }\r
833                 \r
834                 if (date.equalsIgnoreCase("month")) {\r
835                         calendar.add(Calendar.MONTH, offset);\r
836                         calendar.set(Calendar.DAY_OF_MONTH, 1);\r
837                         calendar.set(Calendar.HOUR, 0);\r
838                         calendar.set(Calendar.MINUTE, 0);\r
839                         calendar.set(Calendar.SECOND, 1);\r
840                         found = true;\r
841                 }\r
842 \r
843                 if (date.equalsIgnoreCase("year")) {\r
844                         calendar.add(Calendar.YEAR, offset);\r
845                         calendar.set(Calendar.MONTH, Calendar.JANUARY);\r
846                         calendar.set(Calendar.DAY_OF_MONTH, 1);\r
847                         calendar.set(Calendar.HOUR, 0);\r
848                         calendar.set(Calendar.MINUTE, 0);\r
849                         calendar.set(Calendar.SECOND, 1);\r
850                         found = true;\r
851                 }\r
852 \r
853                 if (date.equalsIgnoreCase("week")) {\r
854                         calendar.add(Calendar.DATE, 0-calendar.get(Calendar.DAY_OF_WEEK)+1);\r
855                         calendar.add(Calendar.DATE,(offset*7));\r
856                         calendar.set(Calendar.HOUR, 0);\r
857                         calendar.set(Calendar.MINUTE, 0);\r
858                         calendar.set(Calendar.SECOND, 1);\r
859 \r
860                         found = true;\r
861                 }\r
862                 \r
863                 // If nothing was found, then we have a date number\r
864                 if (!found) {\r
865                         calendar = stringToGregorianCalendar(date);\r
866                 }\r
867                 \r
868                 \r
869                 String dateTimeFormat = new String("yyyyMMdd-HHmmss");\r
870                 SimpleDateFormat simple = new SimpleDateFormat(dateTimeFormat);\r
871                 StringBuilder creationDate = new StringBuilder(simple.format(noteDate));\r
872                 GregorianCalendar nCalendar = stringToGregorianCalendar(creationDate.toString().replace("-", "T"));\r
873                 if (calendar == null || nCalendar == null)  // If we have something invalid, it automatically fails\r
874                         return 1;\r
875                 return calendar.compareTo(nCalendar);\r
876         }\r
877         private GregorianCalendar stringToGregorianCalendar(String date) {\r
878                 String datePart = date;\r
879                 GregorianCalendar calendar = new GregorianCalendar();\r
880                 boolean GMT = false;\r
881                 String timePart = "";\r
882                 if (date.contains("T")) {\r
883                         datePart = date.substring(0,date.indexOf("T"));\r
884                         timePart = date.substring(date.indexOf("T")+1);\r
885                 } else {\r
886                         timePart = "000001";\r
887                 }\r
888                 if (datePart.length() != 8)\r
889                         return null;\r
890                 calendar.set(Calendar.YEAR, new Integer(datePart.substring(0,4)));\r
891                 calendar.set(Calendar.MONTH, new Integer(datePart.substring(4,6))-1);\r
892                 calendar.set(Calendar.DAY_OF_MONTH, new Integer(datePart.substring(6)));\r
893                 if (timePart.endsWith("Z")) {\r
894                         GMT = true;\r
895                         timePart = timePart.substring(0,timePart.length()-1);\r
896                 }\r
897                 timePart = timePart.concat("000000");\r
898                 timePart = timePart.substring(0,6);\r
899                 calendar.set(Calendar.HOUR, new Integer(timePart.substring(0,2)));\r
900                 calendar.set(Calendar.MINUTE, new Integer(timePart.substring(2,4)));\r
901                 calendar.set(Calendar.SECOND, new Integer(timePart.substring(4)));\r
902                 if (GMT)\r
903                         calendar.set(Calendar.ZONE_OFFSET, -1*(calendar.get(Calendar.ZONE_OFFSET)/(1000*60*60)));\r
904                 return calendar;\r
905 \r
906         }\r
907                 \r
908 }\r