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.rest;
020
021import java.util.ArrayList;
022import java.util.Collection;
023import java.util.HashMap;
024import java.util.List;
025import java.util.Map;
026import java.util.concurrent.ExecutionException;
027
028import net.sf.json.JSONObject;
029
030import org.apache.commons.lang3.StringUtils;
031import org.restlet.data.Form;
032import org.restlet.data.MediaType;
033import org.restlet.data.Status;
034import org.restlet.representation.EmptyRepresentation;
035import org.restlet.representation.Representation;
036import org.restlet.representation.StringRepresentation;
037import org.restlet.resource.Get;
038import org.restlet.resource.ServerResource;
039import org.slf4j.Logger;
040import org.slf4j.LoggerFactory;
041
042import pt.ua.dicoogle.core.QueryExpressionBuilder;
043import pt.ua.dicoogle.core.dim.DIMGeneric;
044import pt.ua.dicoogle.plugins.PluginController;
045import pt.ua.dicoogle.sdk.utils.DictionaryAccess;
046import pt.ua.dicoogle.sdk.datastructs.SearchResult;
047import pt.ua.dicoogle.sdk.task.JointQueryTask;
048import pt.ua.dicoogle.sdk.task.Task;
049
050/**
051 *
052 * @author fmvalente
053 */
054
055
056//TODO:add type to file search
057public class RestDimResource extends ServerResource{
058    
059        private static final Logger log = LoggerFactory.getLogger(RestDimResource.class);
060        
061    @Get
062    public Representation represent(){
063        
064        Form queryForm = getRequest().getResourceRef().getQueryAsForm();
065    
066        String search = queryForm.getValues("q");
067        String advSearch = queryForm.getValues("advq");
068        
069        if(StringUtils.isNotEmpty(search)){
070            QueryExpressionBuilder q = new QueryExpressionBuilder(search);
071            search = q.getQueryString();
072        }else if (StringUtils.isNotEmpty(advSearch)) {
073                        search = advSearch;
074                }else{
075                        //SEND ERROR NO QUERY DEFINED
076                        setStatus(new Status(401), "No Query String Provided: Please provide a query either by ?advq, for advanced searches, or ?q for free text");
077                        return new EmptyRepresentation();
078                }
079        
080        String type = queryForm.getValues("type");
081        boolean dim = true;
082        if(StringUtils.isNotEmpty(type)){
083                if(type.equalsIgnoreCase("DIM")){
084                        dim = true;
085                }else if (type.equalsIgnoreCase("RAW")) {
086                                dim = false;
087                        }else{
088                                //SEND ERROR!! WRONG RETURN TYPE
089                                setStatus(new Status(402), "Wrong return type: Supported types, dim (default), raw.");
090                                
091                                return new EmptyRepresentation();
092                        }
093        }
094        
095        List<String> knownProviders = new ArrayList<String>();
096        String[] providers = queryForm.getValuesArray("provider");
097        List<String> activeProviders = PluginController.getInstance().getQueryProvidersName(true);
098        boolean queryAll = providers.length == 0;
099        for(String p : providers){
100                if(p.equalsIgnoreCase("all")){
101                        queryAll = true;
102                        break;
103                }else if(activeProviders.contains(p)){
104                        knownProviders.add(p);
105                }
106        }
107        activeProviders = null;
108                
109        String[] extraFieldList = queryForm.getValuesArray("field");
110        HashMap<String, String> extraFields = new HashMap<String, String>();
111        //attaches the required extrafields
112        if(extraFieldList.length == 0 || dim){
113            extraFields.put("PatientName", "PatientName");
114            extraFields.put("PatientID", "PatientID");
115            extraFields.put("Modality", "Modality");
116            extraFields.put("StudyDate", "StudyDate");
117            extraFields.put("SeriesInstanceUID", "SeriesInstanceUID");
118            extraFields.put("StudyID", "StudyID");
119            extraFields.put("StudyInstanceUID", "StudyInstanceUID");
120            extraFields.put("Thumbnail", "Thumbnail");
121            extraFields.put("SOPInstanceUID", "SOPInstanceUID");
122        }else{
123            Map<String, String> availableTags = new HashMap<String, String>();
124            for(String tag : DictionaryAccess.getInstance().getTagList().keySet()){
125                availableTags.put(tag.toLowerCase(), tag);
126            }            
127            for(String f : extraFieldList){
128                if(f.equalsIgnoreCase("all")){
129                    for(String k : availableTags.values()){
130                        extraFields.put(k, k);
131                    }
132                    break;
133                }
134                if(availableTags.containsKey(f)){
135                    extraFields.put(availableTags.get(f), availableTags.get(f));
136                }
137            }
138        }
139                
140        //System.err.println("ADVSEARCH: "+advSearch);
141        //System.err.println("FINAL SEARCH QUERY: "+search);
142
143        long startTime = System.currentTimeMillis();
144        MyHolder holder = new MyHolder();
145        if(queryAll)
146                PluginController.getInstance().queryAll(holder, search, extraFields);
147        else
148                PluginController.getInstance().query(holder, knownProviders, search, extraFields);
149        
150        ArrayList<SearchResult> resultsArr = new ArrayList<SearchResult>();
151        
152                try {
153                        Iterable<SearchResult> results = holder.get();
154                
155                        for(SearchResult r : results)
156                        resultsArr.add(r);
157                
158                results = null;
159                
160                } catch (InterruptedException | ExecutionException e) {
161                        // TODO Auto-generated catch block
162                        e.printStackTrace();
163                }
164                startTime = System.currentTimeMillis() - startTime;
165                
166                String ret = "";
167                MediaType mtype = null;
168                if(dim){
169                        ret = processDIMResults(resultsArr);
170                        mtype = MediaType.APPLICATION_XML;                      
171                }else{
172                        ret = processJSON(resultsArr, startTime);
173                        mtype = MediaType.APPLICATION_JSON;
174                }
175                
176                if(StringUtils.isEmpty(ret) && !resultsArr.isEmpty()){
177                        //RAISE ERROR
178                        setStatus(new Status(400), "Error parsing results data:");
179                        return new EmptyRepresentation();
180                }
181        
182        //constructs our xml data struct
183        return new StringRepresentation(ret, mtype);
184    }
185    
186    private static String processDIMResults(Collection<SearchResult> results){
187        DIMGeneric dim = null;
188        try{
189            dim = new DIMGeneric(results);
190            return dim.getXML();
191        }
192        catch (Exception ex) {
193//            LoggerFactory.getLogger(RestDimResource.class).error(ex.getMessage(), ex);
194                ex.printStackTrace();
195        }
196        //and returns an xml version of our dim search
197        return null;
198
199    }
200    
201    private static String processJSON(Collection<SearchResult> results, long elapsedTime){
202        JSONObject resp = new JSONObject();
203        for(SearchResult r : results){
204                JSONObject rj = new JSONObject();
205                rj.put("uri", r.getURI().toString());
206                
207                JSONObject fields = new JSONObject();
208                fields.accumulateAll(r.getExtraData());
209                
210                rj.put("fields", fields);
211                
212                resp.accumulate("results", rj);
213        }
214        resp.put("numResults", results.size());
215        resp.put("elapsedTime", elapsedTime);
216        
217        return resp.toString();
218    }
219    
220    private static class MyHolder extends JointQueryTask{
221
222                @Override
223                public void onCompletion() {
224                        // TODO Auto-generated method stub
225                        
226                }
227
228                @Override
229                public void onReceive(Task<Iterable<SearchResult>> e) {
230                        // TODO Auto-generated method stub
231                        
232                }
233        
234    }
235}