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 */
019/** 
020 * Class SearchResult is responsible to get results from Lucene indexer
021 * But no text results are returned instead we use names of DICOM file and 
022 * instance a new DicomObject, so in theory this is an abstract to a list of 
023 * DicomObject, neither list of *names* of DICOM file.
024 */
025package pt.ua.dicoogle.server;
026
027import java.io.*;
028import java.net.URI;
029import java.net.URISyntaxException;
030
031import org.dcm4che2.data.*;
032import org.slf4j.Logger;
033import pt.ua.dicoogle.core.ServerSettings;
034
035import java.util.ArrayList;
036import java.util.Collection;
037import java.util.HashMap;
038import java.util.Iterator;
039import java.util.List;
040import java.util.concurrent.ExecutionException;
041import org.slf4j.LoggerFactory;
042
043import org.dcm4che2.io.DicomInputStream;
044
045
046import pt.ua.dicoogle.core.dim.*;
047import pt.ua.dicoogle.plugins.PluginController;
048import pt.ua.dicoogle.sdk.datastructs.SearchResult;
049import pt.ua.dicoogle.sdk.task.JointQueryTask;
050import pt.ua.dicoogle.sdk.task.Task;
051/**
052 *
053 * @author Luís A. Bastião Silva <bastiao@ua.pt>
054 * @since 17 Fev 2009
055 */
056public class SearchDicomResult implements Iterator<DicomObject>
057{
058
059    public enum QUERYLEVEL { PATIENT, STUDY, SERIE, IMAGE}
060
061    private final QUERYLEVEL queryLevel; 
062
063
064    /**
065    * Get IndexCore
066    */
067    
068    Collection<SearchResult> list = null ;
069    List<Patient> patientList = new ArrayList<>();
070    List<Study> studyList = new ArrayList<>();
071    List<Serie> seriesList = new ArrayList<>();
072    Iterator it = null ;
073    
074    String currentFile ;
075
076
077
078    private static ConcatTags concatTags = null;
079    private static  boolean concatTagsCheck = true;
080
081
082    private static final Logger logger = LoggerFactory.getLogger(SearchDicomResult.class);
083
084    public SearchDicomResult(String searchQuery, boolean isNetwork,
085                        ArrayList<String> extrafields, QUERYLEVEL level) {
086
087                queryLevel = level;
088
089                /**
090                 * Get the array list of resulst match searchQuery
091                 */
092
093        logger.info("QUERY: " + searchQuery);
094        logger.info("QUERYLEVEL: " + queryLevel);
095
096        if (concatTags==null&& concatTagsCheck)
097        {
098            concatTags = new ConcatTags();
099            try {
100                concatTags.parseConfig(ConcatTags.FILENAME);
101            } catch (FileNotFoundException ex) {
102                logger.info("There is not file: " + ConcatTags.FILENAME);
103                concatTags = null;
104                concatTagsCheck = false;
105            }
106        }
107
108                HashMap<String, String> extraFields = new HashMap<String, String>();
109                for (String s : extrafields) {
110                        extraFields.put(s, s);
111                }
112
113                JointQueryTask holder = new JointQueryTask() {
114
115                        @Override
116                        public void onReceive(Task<Iterable<SearchResult>> e) {
117                                // TODO Auto-generated method stub
118
119                        }
120
121                        @Override
122                        public void onCompletion() {
123                                // TODO Auto-generated method stub
124
125                        }
126                };
127                holder = PluginController.getInstance().queryAll(holder, searchQuery,
128                                extraFields);
129
130                try {
131                        it = holder.get().iterator();
132                        
133                        list = new ArrayList<SearchResult>();
134                        while (it.hasNext()) {
135                                list.add((SearchResult) it.next());
136                        }
137                } catch (InterruptedException | ExecutionException e1) {
138                        // TODO Auto-generated catch block
139                        e1.printStackTrace();
140                }
141
142                if(list != null)
143                        it = list.iterator();
144                
145                if (level == QUERYLEVEL.PATIENT || level == QUERYLEVEL.STUDY) {
146                        DIMGeneric dimModel = null;
147            try
148            {
149                if (concatTags==null)
150                    dimModel = new DIMGeneric(list);
151                else
152                    dimModel = new DIMGeneric(concatTags, list);
153
154            } catch (Exception ex)
155            {
156                ex.printStackTrace();
157            }
158
159                        ArrayList<Patient> listPatients = dimModel.getPatients();
160
161                        for (Patient p : listPatients) {
162                                studyList.addAll(p.getStudies());
163                        }
164
165                        it = studyList.iterator();
166
167                } else if (level == QUERYLEVEL.SERIE) {
168
169            DIMGeneric dimModel = null;
170            try
171            {
172                if (concatTags==null)
173                    dimModel = new DIMGeneric(list);
174                else
175                    dimModel = new DIMGeneric(concatTags, list);
176            } catch (Exception ex)
177            {
178            }
179            
180
181                        ArrayList<Patient> listPatients = dimModel.getPatients();
182                        for (Patient p : listPatients) {
183                                studyList.addAll(p.getStudies());
184                                for (Study s : p.getStudies()) {
185                                        seriesList.addAll(s.getSeries());
186                                }
187                        }
188                        it = seriesList.iterator();
189
190                }
191
192        }
193
194    @Override
195    public boolean hasNext()
196    {
197      if (it!=null)
198      {
199        return it.hasNext();
200      }
201      else
202      {
203        return false;
204      }
205    }
206
207    public String getCurrentFile()
208    {
209        return this.currentFile ; 
210    }
211
212    @Override
213    public DicomObject next()
214    {
215
216        // TODO: this code need to be refactored
217        // C-FIND RSP should be builded based on Search Result,
218        // instead opening the file to build DicomObject.
219
220        /** 
221         * Get the fullpath of images 
222         */
223        ServerSettings s = ServerSettings.getInstance();
224        String path = s.getPath(); 
225        
226        //DebugManager.getInstance().debug("Path of DICOM: "+path);
227
228
229        if (it != null &&  it.hasNext())
230        {
231            Object next = it.next();
232            if (queryLevel==QUERYLEVEL.IMAGE )
233            {
234
235                SearchResult sR = (SearchResult)next;
236                
237                path = sR.getURI().toString();
238                currentFile = path ;
239                //DebugManager.getInstance().debug("-> Next::: " + next.toString());
240                DicomInputStream din = null;
241                /*try
242                {
243                    if (path.endsWith(".gz"))
244                        din = new DicomInputStream(new GZIPInputStream(new BufferedInputStream(new FileInputStream(new File(path)), 256)));
245                    else
246                        din = new DicomInputStream(new File(path));
247                   
248                    
249                    URI uri = new URI(path);
250                    //System.out.println("Trying to find Plugin for: "+uri.toString());
251                    StorageInterface plug = PluginController.getInstance().getStorageForSchema(uri);
252                    
253                    if(plug != null){
254                        //System.out.println("Found Plugin For: "+uri.toString());
255                        
256                        Iterable<StorageInputStream> stream = plug.at(uri);
257                        for(StorageInputStream str : stream)
258                            
259                            try {
260                                din = new DicomInputStream(str.getInputStream());
261                            } catch (IOException ex) {
262                                LoggerFactory.getLogger(SearchDicomResult.class).error(ex.getMessage(), ex);
263                            }
264                    }
265                    
266                    //DebugManager.getInstance().debug("Imagem: "+path+"..."+next);
267                } catch (URISyntaxException ex) {
268                    LoggerFactory.getLogger(SearchDicomResult.class).error(ex.getMessage(), ex);
269                }
270                */
271                
272                /** This code is refactored in a experimental branch
273                 * Building a BasicDicomObject based on Indexing
274                 * It will increase the performace
275                 */
276                BasicDicomObject result = new BasicDicomObject();
277
278                // Fill fields of study now
279
280
281                //System.out.println("Serie : "+ serieTmp);
282                result.putString(Tag.InstitutionName, VR.CS,(String)sR.get("InstitutionName"));
283
284                result.putString(Tag.StudyInstanceUID, VR.UI, (String)sR.get("StudyInstanceUID"));
285                result.putString(Tag.SeriesInstanceUID, VR.UI, (String)sR.get("SeriesInstanceUID"));
286                result.putString(Tag.SOPInstanceUID, VR.UI, (String)sR.get("SOPInstanceUID"));
287                result.putString(Tag.SeriesDescription, VR.LO, (String)sR.get("SeriesDescription"));
288                result.putString(Tag.SeriesDate, VR.TM, (String)sR.get("SeriesDate"));
289                result.putString(Tag.SeriesTime, VR.TM, (String)sR.get("SeriesTime"));
290                result.putString(Tag.QueryRetrieveLevel, VR.LO, "IMAGE");
291
292                result.putString(Tag.Modality, VR.CS,(String)sR.get("Modality"));
293
294                result.putString(Tag.SeriesNumber, VR.IS, "" + (String)sR.get("SeriesNumber"));
295
296
297                return result;
298
299            }
300            else if (queryLevel == QUERYLEVEL.STUDY||queryLevel == QUERYLEVEL.PATIENT)
301            {
302
303                Study studyTmp = (Study)next;
304                BasicDicomObject result = new BasicDicomObject();
305                String patientName =studyTmp.getParent().getPatientName() ;
306                
307                try {
308                    patientName = new String(studyTmp.getParent().getPatientName().getBytes("ISO-8859-1"), "ISO-8859-1");
309                } catch (Exception ex) {
310                    LoggerFactory.getLogger(SearchDicomResult.class).error(ex.getMessage(), ex);
311                }
312                try {
313                    result.putBytes(Tag.PatientName, VR.PN, patientName.getBytes("ISO-8859-1"));
314                } catch (Exception ex) {
315                    LoggerFactory.getLogger(SearchDicomResult.class).error(ex.getMessage(), ex);
316                }
317                
318                //System.out.println("PatientName:"+patientName);
319                result.putString(Tag.SpecificCharacterSet, VR.CS, "ISO_IR 100");
320                result.putString(Tag.PatientSex, VR.LO, studyTmp.getParent().getPatientSex());
321                result.putString(Tag.PatientID, VR.LO, studyTmp.getParent().getPatientID());
322                result.putString(Tag.PatientBirthDate, VR.DA, studyTmp.getParent().getPatientBirthDate());
323                result.putString(Tag.StudyDate, VR.DA, studyTmp.getStudyData());
324                result.putString(Tag.StudyID, VR.SH, studyTmp.getStudyID());
325                result.putString(Tag.StudyTime, VR.TM, studyTmp.getStudyTime());
326                result.putString(Tag.AccessionNumber, VR.SH, studyTmp.getAccessionNumber());
327                result.putString(Tag.StudyInstanceUID, VR.UI, studyTmp.getStudyInstanceUID());
328                result.putString(Tag.StudyDescription, VR.LO, studyTmp.getStudyDescription());
329                String modality = studyTmp.getSeries().get(0).getModality(); // Point of Failure, fix me
330                result.putString(Tag.ModalitiesInStudy, VR.CS,modality);
331                result.putString(Tag.Modality, VR.CS,modality);
332                result.putString(Tag.InstitutionName, VR.CS, studyTmp.getInstitutuionName());
333
334                int instances = 0;
335                for (Serie serieTmp : studyTmp.getSeries())
336                {
337                    instances+=serieTmp.getImageList().size();
338                }
339
340                result.putString(Tag.NumberOfStudyRelatedInstances, VR.IS,""+instances);
341                result.putString(Tag.NumberOfSeriesRelatedInstances, VR.IS,""+studyTmp.getSeries().size());
342
343
344                return result;
345                
346            }
347            else if (queryLevel == QUERYLEVEL.SERIE)
348            {
349                // Serie
350
351                Serie serieTmp = (Serie)next;
352                BasicDicomObject result = new BasicDicomObject();
353                //System.out.println("Serie : "+ serieTmp);
354                result.putString(Tag.InstitutionName, VR.CS,serieTmp.getParent().getInstitutuionName());
355                
356                result.putString(Tag.StudyInstanceUID, VR.UI, serieTmp.getParent().getStudyInstanceUID());
357                result.putString(Tag.SeriesInstanceUID, VR.UI, serieTmp.getSerieInstanceUID());
358                result.putString(Tag.SeriesDescription, VR.LO, serieTmp.getSeriesDescription());
359                result.putString(Tag.SeriesDate, VR.TM, serieTmp.getSeriesDate());
360                result.putString(Tag.QueryRetrieveLevel, VR.LO, "SERIES");
361                String modality = serieTmp.getModality(); // Point of Failure, fix me
362                result.putString(Tag.Modality, VR.CS,modality);
363                
364                result.putString(Tag.SeriesNumber, VR.IS, "" + serieTmp.getSerieNumber());
365
366
367                result.putString(Tag.Modality, VR.CS,modality);
368                if (serieTmp.getModality().equals("MG")||serieTmp.getModality().equals("CR"))
369                {
370
371                    result.putString(Tag.ViewPosition, null, serieTmp.getViewPosition());
372                    result.putString(Tag.ImageLaterality, null, serieTmp.getImageLaterality());
373                    result.putString(Tag.AcquisitionDeviceProcessingDescription, VR.AE, serieTmp.getAcquisitionDeviceProcessingDescription());
374                    DicomElement viewCodeSequence = result.putSequence(Tag.ViewCodeSequence);
375                    DicomObject viewCodeSequenceObj = new BasicDicomObject();
376                    viewCodeSequenceObj.setParent(result);
377                    viewCodeSequenceObj.putString(Tag.CodeValue, null, serieTmp.getViewCodeSequence_CodeValue());
378                    viewCodeSequenceObj.putString(Tag.CodingSchemeDesignator, null, serieTmp.getViewCodeSequence_CodingSchemeDesignator());
379                    viewCodeSequenceObj.putString(Tag.CodingSchemeVersion, null, serieTmp.getViewCodeSequence_CodingSchemeVersion());
380                    viewCodeSequenceObj.putString(Tag.CodeMeaning, null, serieTmp.getViewCodeSequence_CodeMeaning());
381
382                    viewCodeSequence.addDicomObject(viewCodeSequenceObj);
383                    result.putNestedDicomObject(Tag.ViewCodeSequence, viewCodeSequenceObj);
384                }
385                result.putString(Tag.NumberOfSeriesRelatedInstances, VR.IS,""+serieTmp.getImageList().size());
386
387
388                result.putString(Tag.SeriesNumber, VR.IS, "" + serieTmp.getSerieNumber());
389                result.putString(Tag.ProtocolName, VR.LO, "" + serieTmp.getProtocolName());
390                result.putString(Tag.BodyPartThickness, VR.LO, "" + serieTmp.getBodyPartThickness());
391
392
393                return result;
394
395            }
396            else
397            {
398                System.err.println("ERROR: WRONG QUERY LEVEL!");
399            }
400            
401
402        }    
403        return null ; 
404    }
405
406    @Override
407    public void remove()
408    {
409        throw new UnsupportedOperationException("Not supported. Nobody use it.");
410    }
411}