001/**
002 * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
003 *
004 * This file is part of Dicoogle/dicoogle.
005 *
006 * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
007 * it under the terms of the GNU General Public License as published by
008 * the Free Software Foundation, either version 3 of the License, or
009 * (at your option) any later version.
010 *
011 * Dicoogle/dicoogle is distributed in the hope that it will be useful,
012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
014 * GNU General Public License for more details.
015 *
016 * You should have received a copy of the GNU General Public License
017 * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
018 */
019package pt.ua.dicoogle.server.web.dicom;
020
021import static pt.ua.dicoogle.server.web.utils.Query.addExtraQueryParam;
022
023import java.io.UnsupportedEncodingException;
024import java.text.SimpleDateFormat;
025import java.util.ArrayList;
026import java.util.Calendar;
027import java.util.Collection;
028import java.util.Collections;
029import java.util.HashMap;
030import java.util.HashSet;
031import java.util.List;
032import java.util.Set;
033import java.util.concurrent.ExecutionException;
034import org.slf4j.LoggerFactory;
035
036import javax.servlet.ServletRequest;
037import javax.servlet.http.HttpServletRequest;
038import javax.servlet.http.HttpSession;
039
040import net.sf.json.JSONArray;
041import net.sf.json.JSONObject;
042import pt.ua.dicoogle.core.QueryExpressionBuilder;
043import pt.ua.dicoogle.plugins.PluginController;
044import pt.ua.dicoogle.sdk.utils.DictionaryAccess;
045import pt.ua.dicoogle.sdk.datastructs.SearchResult;
046import pt.ua.dicoogle.sdk.settings.Utils;
047import pt.ua.dicoogle.sdk.task.JointQueryTask;
048import pt.ua.dicoogle.sdk.task.Task;
049
050/**
051 * A simple class used by the Dicoogle Web interface that allow web users to
052 * have the same searching capabilities of desktop application users. 
053 * 
054 * The new version of these class generates the query tasks. These tasks take into
055 * account the multiple available providers. The search task is then placed in a SearchHolder
056 * especially created to the issuing user. This holder is accessible via /search/holders.
057 * 
058 * @author Tiago Marques Godinho
059 * @author António Novo <antonio.novo@ua.pt>
060 */
061public class Search {
062        private List<String> selectedProviders;
063
064        /**
065         * Is this an advanced search?
066         */
067        private boolean isAdvanced;
068
069        /**
070         * Simple query string.
071         */
072        private String simpleQuery;
073        /**
074         * If the simple query string is keyword based.
075         */
076        private boolean keyworded;
077
078        /**
079         * How long did the search procedure take to complete, in milliseconds.
080         */
081        private long timeTaken;
082
083        /**
084         * Advanced search params.
085         */
086        private String patientName;
087        private String patientID;
088        private String patientGender;
089        private String institutionName;
090        private String physician;
091        private String operatorName;
092        private String studyDateFormat;
093        private String exactDate;
094        private boolean useStartDate;
095        private boolean useEndDate;
096        private String startDate;
097        private String endDate;
098        private boolean modCR;
099        private boolean modMG;
100        private boolean modPT;
101        private boolean modXA;
102        private boolean modES;
103        private boolean modCT;
104        private boolean modMR;
105        private boolean modRF;
106        private boolean modUS;
107        private boolean modDX;
108        private boolean modNM;
109        private boolean modSC;
110        private boolean modOT;
111        private boolean modOthers;
112
113        /**
114         * Final query string.
115         */
116        private String finalQuery;
117
118        /**
119         * Lists of search results in various forms.
120         */
121        private Collection<SearchResult> searchResults;
122
123        /**
124         * If the result list is supposed to have all the extra fields (servlet XML
125         * request) or just the minimum (webapp search).
126         */
127        private boolean fullRequest;
128
129        private HttpSession httpSession;
130
131        private int searchID;
132
133        @SuppressWarnings("unchecked")
134        public Search(ServletRequest request) {
135                this.searchID = -1;
136                // reset all the internal properties
137                isAdvanced = false;
138                simpleQuery = null;
139                patientName = null;
140                patientID = null;
141                patientGender = null;
142                institutionName = null;
143                physician = null;
144                operatorName = null;
145                studyDateFormat = null;
146                exactDate = null;
147                useStartDate = false;
148                useEndDate = false;
149                startDate = null;
150                endDate = null;
151                modCR = false;
152                modMG = false;
153                modPT = false;
154                modXA = false;
155                modES = false;
156                modCT = false;
157                modMR = false;
158                modRF = false;
159                modUS = false;
160                modDX = false;
161                modNM = false;
162                modSC = false;
163                modOT = false;
164                modOthers = false;
165                finalQuery = null;
166                searchResults = null;
167                fullRequest = false;
168
169                // this ensures that any special characters won't be parsed incorrectly
170                try {
171                        request.setCharacterEncoding("UTF-8");
172                } catch (UnsupportedEncodingException ex) {
173                        // do nothing
174                }
175
176                // get the query method (either default or advanced)
177                String method = request.getParameter("method");
178
179                // see if we should parse the request as simple or advanced search
180                if ((method != null) && (!method.isEmpty())) {
181                        if (method.equalsIgnoreCase("Advanced")) // advanced search
182                        {
183                                isAdvanced = true;
184                        }
185                }
186
187                // and now mount the proper query
188                if (isAdvanced) {
189                        mountAdvancedSearch(request);
190                } else {
191                        mountSimpleSearch(request);
192                }
193
194                String qp = request.getParameter("queryProviders");
195
196                System.out.println("QueryProviders: " + qp);
197                JSONArray arr = JSONArray.fromObject(qp);
198
199                System.out.println("QueryProviders: " + qp);
200                if (qp != null) {
201                        this.selectedProviders = new ArrayList<>();
202                        this.selectedProviders.addAll(JSONArray.toCollection(arr,
203                                        String.class));
204                } else {
205                        this.selectedProviders = PluginController.getInstance()
206                                        .getQueryProvidersName(true);
207                }
208                this.httpSession = ((HttpServletRequest) request).getSession(false);
209        }
210
211        private void mountSimpleSearch(ServletRequest request) {
212                // get the only param of this simple query
213                simpleQuery = request.getParameter("query");
214                keyworded = Utils.parseCheckBoxValue(request.getParameter("keywords"));
215
216                // parse the user query into an expression
217                if ((simpleQuery != null) && (!simpleQuery.trim().isEmpty())) // if the
218                                                                                                                                                // query
219                                                                                                                                                // is
220                                                                                                                                                // not
221                                                                                                                                                // empty...
222                {
223                        // ... build a query expression based on it and get its resulting
224                        // query string
225                        if (!isKeyworded()) {
226                                // write the QueryString respecting BNF grammer defined
227                                // regarding Lucene documentation 2.4.X branch
228                                QueryExpressionBuilder exp = new QueryExpressionBuilder(
229                                                simpleQuery);
230                                finalQuery = exp.getQueryString();
231                        } else {
232                                finalQuery = simpleQuery;
233                        }
234                } else {
235                        finalQuery = "*:*"; // default query string
236                }
237        }
238
239        private void mountAdvancedSearch(ServletRequest request) {
240                isAdvanced = true;
241
242                // get all the params defined on this advanced query
243                patientName = request.getParameter("patientName");
244                patientID = request.getParameter("patientID");
245                patientGender = request.getParameter("patientGender");
246                institutionName = request.getParameter("institutionName");
247                physician = request.getParameter("physician");
248                operatorName = request.getParameter("operatorName");
249                studyDateFormat = request.getParameter("studyDate");
250                exactDate = request.getParameter("exactDate");
251                useStartDate = Utils.parseCheckBoxValue(request
252                                .getParameter("fromDate"));
253                useEndDate = Utils.parseCheckBoxValue(request.getParameter("toDate"));
254                startDate = request.getParameter("startDate");
255                endDate = request.getParameter("endDate");
256                modCR = Utils.parseCheckBoxValue(request.getParameter("modCR"));
257                modMG = Utils.parseCheckBoxValue(request.getParameter("modMG"));
258                modPT = Utils.parseCheckBoxValue(request.getParameter("modPT"));
259                modXA = Utils.parseCheckBoxValue(request.getParameter("modXA"));
260                modES = Utils.parseCheckBoxValue(request.getParameter("modES"));
261                modCT = Utils.parseCheckBoxValue(request.getParameter("modCT"));
262                modMR = Utils.parseCheckBoxValue(request.getParameter("modMR"));
263                modRF = Utils.parseCheckBoxValue(request.getParameter("modRF"));
264                modUS = Utils.parseCheckBoxValue(request.getParameter("modUS"));
265                modDX = Utils.parseCheckBoxValue(request.getParameter("modDX"));
266                modNM = Utils.parseCheckBoxValue(request.getParameter("modNM"));
267                modSC = Utils.parseCheckBoxValue(request.getParameter("modSC"));
268                modOT = Utils.parseCheckBoxValue(request.getParameter("modOT"));
269                modOthers = Utils.parseCheckBoxValue(request.getParameter("modOthers"));
270
271                // and form the query string
272                finalQuery = getAdvancedQuery();
273        }
274
275        /**
276         * Returns a String with a valid query, that can be combined with others if
277         * needed, for searching for all modalities currently defined on the web
278         * interface (supported directly, minus the Others).
279         * 
280         * @return a String with a valid query, that can be combined with others if
281         *         needed, for searching for all modalities currently defined on the
282         *         web interface (supported directly, minus the Others).
283         */
284        private List<String> getAllDefinedModalitiesQuery() {
285                List<String> ret = new ArrayList<>(13);
286
287                                ret.add("CR");
288                                ret.add("CT");
289                                ret.add("DX");
290                                ret.add("ES");
291                                ret.add("MG");
292                                ret.add("MR");
293                                ret.add("NM");
294                                ret.add("OT");
295                                ret.add("PT");
296                                ret.add("RF");
297                                ret.add("SC");
298                                ret.add("US");
299                                ret.add("XA");             
300
301                return ret;
302        }
303
304        /**
305         * Based on the set of optional advanced search params, returns a advanced
306         * query string that reflects those params.
307         * 
308         * @return an advanced query string for the params that match their values.
309         */
310        public String getAdvancedQuery() {
311                String result = "";
312
313                // patient name
314                if ((patientName != null) && (!patientName.isEmpty())) {
315                        result = addExtraQueryParam(result, "PatientName:(" + patientName
316                                        + ")");
317                }
318
319                // patient id
320                if ((patientID != null) && (!patientID.isEmpty())) {
321                        result = addExtraQueryParam(result, "PatientID:(" + patientID + ")");
322                }
323
324                // patient gender
325                if ((patientGender != null) && (!patientGender.isEmpty())
326                                && (!isPatientGenderAll())) {
327                        if (isPatientGenderMale()) {
328                                result = addExtraQueryParam(result, "PatientSex:M");
329                        } else {
330                                if (isPatientGenderFemale()) {
331                                        result = addExtraQueryParam(result, "PatientSex:F");
332                                }
333                        }
334                }
335
336                // institution name
337                if ((institutionName != null) && (!institutionName.isEmpty())) {
338                        result = addExtraQueryParam(result, "InstitutionName:("
339                                        + institutionName + ")");
340                }
341
342                // physician
343                if ((physician != null) && (!physician.isEmpty())) {
344                        result = addExtraQueryParam(result, "(PerformingPhysicianName:("
345                                        + physician + ") OR ReferringPhysicianName:(" + physician
346                                        + "))");
347                }
348
349                // operator name
350                if ((operatorName != null) && (!operatorName.isEmpty())) {
351                        result = addExtraQueryParam(result, "OperatorName:(" + operatorName
352                                        + ")");
353                }
354
355                // study date
356                if ((studyDateFormat != null) && (!studyDateFormat.isEmpty())) {
357                        if (studyDateFormat.equalsIgnoreCase("Exact")) {
358                                if ((exactDate != null) && (!exactDate.isEmpty()))
359                                        result = addExtraQueryParam(result, "StudyDate:("
360                                                        + exactDate + ")");
361                        } else {
362                                if (studyDateFormat.equalsIgnoreCase("Range")) {
363                                        String date = "StudyDate:[";
364
365                                        if (useStartDate && (startDate != null)
366                                                        && (!startDate.isEmpty())) {
367                                                date += startDate;
368                                        } else {
369                                                date += "0000101";
370                                        }
371                                        date += " TO ";
372                                        if (useEndDate && (endDate != null) && (!endDate.isEmpty())) {
373                                                date += endDate;
374                                        } else {
375                                                Calendar cal = Calendar.getInstance();
376                                                SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
377
378                                                date += sdf.format(cal.getTime());
379                                        }
380
381                                        date += "]";
382
383                                        result = addExtraQueryParam(result, date);
384                                }
385                        }
386                }
387
388                // modalities
389                {
390                        String modalities = "";
391                                                Set<String> mods = new HashSet<String>();
392                        
393                        
394                                                 if (modCR) {
395                                                                mods.add("CR");
396                                                    }
397                                                        if (modCT) {
398                                                                mods.add("CT");
399                                                        }
400                                                        if (modDX) {
401                                                                mods.add("DX");
402                                                        }
403                                                        if (modES) {
404                                                                mods.add("ES");
405                                                        }
406                                                        if (modMG) {
407                                                                mods.add("MG");
408                                                        }
409                                                        if (modMR) {
410                                                                mods.add("MR");
411                                                        }
412                                                        if (modNM) {
413                                                                mods.add("NM");
414                                                        }
415                                                        if (modOT) {
416                                                                mods.add("OT");
417                                                        }
418                                                        if (modPT) {
419                                                                mods.add("PT");
420                                                        }
421                                                        if (modRF) {
422                                                                mods.add("RF");
423                                                        }
424                                                        if (modSC) {
425                                                                mods.add("SC");
426                                                        }
427                                                        if (modUS) {
428                                                                mods.add("US");
429                                                        }
430                                                        if (modXA) {
431                                                                mods.add("XA");
432                                                        }
433                                                                                
434                                                        for(String s : mods){
435                                                            modalities+=s +" ";
436                                                        }
437                                                        
438                                                        if(modOthers){
439                                                            for(String s : getAllDefinedModalitiesQuery()){
440                                                                if(!mods.contains(s))
441                                                                    modalities += "-"+s+" ";
442                                                            }
443                                                        }                                                       
444                                                
445                        // and add the modalities to the resulting query
446                        if (!modalities.isEmpty()) {
447                                result = addExtraQueryParam(result, "Modality:(" + modalities + ")");
448                        }
449                }
450
451                // if no "options" were modified then use the default query string
452                if (result.isEmpty()) {
453                        result = "*:*";
454                }
455
456                return result;
457        }
458
459        /**
460         * Returns if there is a query to be used (NOTE: an empty string is still a
461         * valid query!).
462         * 
463         * @return if there is a query to be used.
464         */
465        public boolean hasQuery() {
466                return ((!isAdvanced) && (simpleQuery != null)) || isAdvanced;
467        }
468
469        /**
470         * Returns the original query.
471         * 
472         * @return the original query.
473         */
474        public String getSimpleQuery() {
475                return simpleQuery;
476        }
477
478        /**
479         * Returns the final query.
480         * 
481         * @return the final query.
482         */
483        public String getFinalQuery() {
484                return finalQuery;
485        }
486
487        /**
488         * Returns a list with the search results for the query.
489         * 
490         * @return a list with the search results for the query.
491         */
492        @Deprecated
493        public Collection<SearchResult> getSearchResults() {
494                // if there is no valid query then abort
495                if (!hasQuery())
496                        return null;
497
498                // if the value is not cached then do the search and cache it
499                if (searchResults == null) {
500                        // perform the search
501                        long startime = System.nanoTime();
502                        searchResults = search(finalQuery, fullRequest);
503                        long endTime = System.nanoTime();
504                        // update the time taken for the search to complete
505                        timeTaken = (endTime - startime) / 1000000;
506                }
507
508                return searchResults;
509        }
510
511        /**
512         * Returns the Selected Query Providers in the JSON Format
513         * @return The selected Query Providers
514         */
515        public String getQueryProvidersJSON() {
516
517                JSONArray arr = new JSONArray();
518
519                for (String p : getQueryProviders()) {
520                        JSONObject obj = new JSONObject();
521                        obj.put("name", p);
522                        boolean sel = this.selectedProviders.contains(p);
523                        obj.put("selected", sel);
524                        arr.add(obj);
525                }
526
527                return arr.toString();
528        }
529
530        /**
531         * Returns a List containing the Selected Query Providers
532         * @return The selected Query Providers 
533         */
534        public List<String> getQueryProviders() {
535                List<String> providers = PluginController.getInstance()
536                                .getQueryProvidersName(true);
537
538                return providers;
539        }
540
541        /**
542         * @return
543         */
544        public List<String> getSelectedProviders() {
545                return this.selectedProviders;
546        }
547
548        /**
549         * Places a new search in the SearchHolder
550         * @param query The query String
551         * @return The Given Query Identifier
552         */
553        private int fireSearch(String query) {
554                if (selectedProviders.isEmpty())
555                        return -1;
556
557                HashMap<String, String> searchParam = new HashMap<>();
558
559                searchParam.put("PatientName", "PatientName");
560                searchParam.put("Modality", "Modality");
561                searchParam.put("StudyDate", "StudyDate");
562                searchParam.put("SOPInstanceUID", "SOPInstanceUID");
563                searchParam.put("Thumbnail", "Thumbnail");
564                searchParam.put("StudyDescription", "StudyDescription");
565                searchParam.put("InstitutionName", "InstitutionName");
566                searchParam.put("SeriesDescription", "SeriesDescription");
567                searchParam.put("PatientID", "PatientID");
568                searchParam.put("PatientSex", "PatientSex");
569
570                if (httpSession == null)
571                        return -1;
572
573                SearchHolder holder = (SearchHolder) httpSession
574                                .getAttribute("dicoogle.web.queryHolder");
575                if (holder == null) {
576                        holder = new SearchHolder();
577                        httpSession.setAttribute("dicoogle.web.queryHolder", holder);
578                }
579
580                int id = holder.registerNewQuery(selectedProviders, query, searchParam);
581
582                return id;
583        }
584
585        /**
586         * Places the search in the Holder. If it has not been done before.
587         * @return
588         */
589        public int placeSearchOrder() {
590                // if there is no valid query then abort
591                if (!hasQuery())
592                        return -1;
593
594                        
595                // performs the search, if it hasn't already
596                if(searchID == -1)
597                        searchID = fireSearch(finalQuery);
598
599                return searchID;
600        }
601
602        /**
603         * Performs a simple search.
604         * 
605         * @param query
606         *            the user entered query.
607         * @return a list of SearchResult objects.
608         */
609        @Deprecated
610        private Collection<SearchResult> search(String query, boolean fullRequest) {
611                if (selectedProviders.isEmpty())
612                        return Collections.emptyList();
613                // get the search results for this query
614                // results = idx.searchSync(query, (fullRequest ? extraFieldsFull :
615                // extraFields));
616
617                List<SearchResult> targetCollection = new ArrayList<SearchResult>();
618                Iterable<SearchResult> itResults = null;
619
620                HashMap<String, String> searchParam = new HashMap<>();
621
622                searchParam.put("PatientName", "PatientName");
623                searchParam.put("Modality", "Modality");
624                searchParam.put("StudyDate", "StudyDate");
625                searchParam.put("SOPInstanceUID", "SOPInstanceUID");
626                searchParam.put("Thumbnail", "Thumbnail");
627                searchParam.put("StudyDescription", "StudyDescription");
628                searchParam.put("InstitutionName", "InstitutionName");
629                searchParam.put("SeriesDescription", "SeriesDescription");
630                searchParam.put("PatientID", "PatientID");
631                searchParam.put("PatientSex", "PatientSex");
632                try {
633                        // for(String provider : selectedProviders){
634                        // System.out.println("Searching in Provider: "+provider);
635                        JointQueryTask t = new JointQueryTask() {
636
637                                @Override
638                                public void onReceive(Task<Iterable<SearchResult>> e) {
639                                        // TODO Auto-generated method stub
640
641                                }
642
643                                @Override
644                                public void onCompletion() {
645                                        // TODO Auto-generated method stub
646
647                                }
648                        };
649                        itResults = PluginController.getInstance()
650                                        .query(t, selectedProviders, query, searchParam).get();
651
652                        // }
653
654                } catch (InterruptedException | ExecutionException ex) {
655                        LoggerFactory.getLogger(Search.class).error(ex.getMessage(), ex);
656                }
657
658                if (itResults == null)
659                        return Collections.emptyList();
660
661                for (SearchResult s : itResults) {
662                        targetCollection.add(s);
663                }
664
665                // and return them
666                return targetCollection;
667        }
668
669        /**
670         * @return the isAdvanced
671         */
672        public boolean isAdvancedQuery() {
673                return isAdvanced;
674        }
675
676        /**
677         * @return the patientName
678         */
679        public String getPatientName() {
680                return patientName;
681        }
682
683        /**
684         * @return the patientID
685         */
686        public String getPatientID() {
687                return patientID;
688        }
689
690        /**
691         * @return the patientGender
692         */
693        public String getPatientGender() {
694                return patientGender;
695        }
696
697        public boolean isPatientGenderAll() {
698                return (patientGender == null)
699                                || patientGender.isEmpty()
700                                || patientGender.equalsIgnoreCase("All")
701                                || ((!patientGender.equalsIgnoreCase("Male")) && (!patientGender
702                                                .equalsIgnoreCase("Female")));
703        }
704
705        public boolean isPatientGenderMale() {
706                return (patientGender != null)
707                                && patientGender.equalsIgnoreCase("Male");
708        }
709
710        public boolean isPatientGenderFemale() {
711                return (patientGender != null)
712                                && patientGender.equalsIgnoreCase("Female");
713        }
714
715        /**
716         * @return the institutionName
717         */
718        public String getInstitutionName() {
719                return institutionName;
720        }
721
722        /**
723         * @return the physician
724         */
725        public String getPhysician() {
726                return physician;
727        }
728
729        /**
730         * @return the operatorName
731         */
732        public String getOperatorName() {
733                return operatorName;
734        }
735
736        /**
737         * @return the studyDateFormat
738         */
739        public String getStudyDateFormat() {
740                return studyDateFormat;
741        }
742
743        public boolean isExactDate() {
744                return (studyDateFormat != null) && (!studyDateFormat.isEmpty())
745                                && studyDateFormat.equalsIgnoreCase("Exact");
746        }
747
748        public boolean isRangedDate() {
749                return (studyDateFormat != null) && (!studyDateFormat.isEmpty())
750                                && studyDateFormat.equalsIgnoreCase("Range");
751        }
752
753        /**
754         * @return the exactDate
755         */
756        public String getExactDate() {
757                return exactDate;
758        }
759
760        /**
761         * @return the useStartDate
762         */
763        public boolean isUseStartDate() {
764                return useStartDate;
765        }
766
767        /**
768         * @return the useEndDate
769         */
770        public boolean isUseEndDate() {
771                return useEndDate;
772        }
773
774        /**
775         * @return the startDate
776         */
777        public String getStartDate() {
778                return startDate;
779        }
780
781        /**
782         * @return the endDate
783         */
784        public String getEndDate() {
785                return endDate;
786        }
787
788        /**
789         * @return the modCR
790         */
791        public boolean isModCR() {
792                return modCR;
793        }
794
795        /**
796         * @return the modMG
797         */
798        public boolean isModMG() {
799                return modMG;
800        }
801
802        /**
803         * @return the modPT
804         */
805        public boolean isModPT() {
806                return modPT;
807        }
808
809        /**
810         * @return the modXA
811         */
812        public boolean isModXA() {
813                return modXA;
814        }
815
816        /**
817         * @return the modES
818         */
819        public boolean isModES() {
820                return modES;
821        }
822
823        /**
824         * @return the modCT
825         */
826        public boolean isModCT() {
827                return modCT;
828        }
829
830        /**
831         * @return the modMR
832         */
833        public boolean isModMR() {
834                return modMR;
835        }
836
837        /**
838         * @return the modRF
839         */
840        public boolean isModRF() {
841                return modRF;
842        }
843
844        /**
845         * @return the modUS
846         */
847        public boolean isModUS() {
848                return modUS;
849        }
850
851        /**
852         * @return the modDX
853         */
854        public boolean isModDX() {
855                return modDX;
856        }
857
858        /**
859         * @return the modNM
860         */
861        public boolean isModNM() {
862                return modNM;
863        }
864
865        /**
866         * @return the modSC
867         */
868        public boolean isModSC() {
869                return modSC;
870        }
871
872        /**
873         * @return the modOT
874         */
875        public boolean isModOT() {
876                return modOT;
877        }
878
879        /**
880         * @return the modOthers
881         */
882        public boolean isModOthers() {
883                return modOthers;
884        }
885
886        /**
887         * @return the keyworded
888         */
889        public boolean isKeyworded() {
890                return keyworded;
891        }
892
893        /**
894         * @return the time taken for the search to complete in milliseconds.
895         */
896        public long getTimeTaken() {
897                return timeTaken;
898        }
899        
900        public static String getAllTags(){
901                List<String> tags = new ArrayList<String>( DictionaryAccess.getInstance().getTagList().keySet() );
902                Collections.sort(tags);
903                JSONArray arr = JSONArray.fromObject(tags);
904                return arr.toString();          
905        }
906}