OSDN Git Service

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