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 * 
021 * The Goal of this class is based on DicomObject 
022 * send FindRSP to destination entity 
023 * 
024 * It will search data at Index of Lucene 
025 * 
026 */
027package pt.ua.dicoogle.server.queryretrieve;
028
029import aclmanager.core.LuceneQueryACLManager;
030import aclmanager.models.Principal;
031
032import java.io.IOException;
033import java.util.ArrayList;
034import org.slf4j.Logger;
035import org.slf4j.LoggerFactory;
036import org.slf4j.Logger;
037import org.slf4j.LoggerFactory;
038
039import org.dcm4che2.data.DicomElement;
040import org.dcm4che2.data.DicomObject;
041import org.dcm4che2.data.Tag;
042import org.dcm4che2.data.VR;
043import org.dcm4che2.net.Association;
044import org.dcm4che2.net.DimseRSP;
045import org.dcm4che2.net.Status;
046
047
048import pt.ua.dicoogle.core.exceptions.CFindNotSupportedException;
049import pt.ua.dicoogle.server.SearchDicomResult;
050
051/**
052 *
053 * @author Luís A. Bastião Silva <bastiao@ua.pt>
054 */
055public class FindRSP implements DimseRSP 
056{
057    
058    private DicomObject rsp;
059    private DicomObject keys;
060    
061    
062    
063    /** 
064     * Each moment in timeline we're getting a item
065     */
066    private DicomObject mwl = null;
067
068    SearchDicomResult search = null ; 
069    
070    private String callingAET;
071    private LuceneQueryACLManager luke;
072    
073    public FindRSP(DicomObject keys, DicomObject rsp, String callingAET, LuceneQueryACLManager luke)
074    {
075        this.rsp = rsp ; 
076        this.keys = keys ;
077        
078        this.callingAET = callingAET;
079        this.luke = luke;
080        
081        
082        /** Debug - show keys, rsp, index */ 
083        if (keys!=null)
084        {
085            //DebugManager.getInstance().debug("keys object: ");
086            //DebugManager.getInstance().debug(keys.toString());
087        }
088        if (rsp!=null)
089        {
090            //DebugManager.getInstance().debug("Rsp object");
091            //DebugManager.getInstance().debug(rsp.toString());
092        }
093        
094        /** 
095         * Get object to search
096         */
097        ArrayList<String> extrafields  = null ;
098        extrafields = new ArrayList<String>();
099
100        extrafields.add("PatientName");
101        extrafields.add("PatientSex");
102        extrafields.add("PatientID");
103        extrafields.add("Modality");
104        extrafields.add("StudyDate");
105        extrafields.add("StudyTime");
106        extrafields.add("AccessionNumber");
107        extrafields.add("StudyID");
108        extrafields.add("StudyDescription");
109        extrafields.add("SeriesNumber");
110        extrafields.add("SeriesInstanceUID");
111        extrafields.add("SeriesDescription");
112        extrafields.add("ReferringPhysicianName");
113        extrafields.add("PatientBirthDate");
114        extrafields.add("ModalitiesInStudy");
115        extrafields.add("StudyInstanceUID");
116        extrafields.add("InstitutionName");
117        extrafields.add("AcquisitionDeviceProcessingDescription");
118        extrafields.add("ProtocolName");
119
120        extrafields.add("SeriesDate");
121
122        extrafields.add("OperatorsName");
123        extrafields.add("RequestingPhysician");
124        extrafields.add("BodyPartThickness");
125        extrafields.add("PatientOrientation");
126        extrafields.add("CompressionForce");
127
128        extrafields.add("ViewPosition");
129        extrafields.add("ImageLaterality");
130        extrafields.add("AcquisitionDeviceProcessingDescription");
131
132
133        extrafields.add("ViewCodeSequence_CodeValue");
134        extrafields.add("ViewCodeSequence_CodingSchemeDesignator");
135        extrafields.add("ViewCodeSequence_CodingSchemeVersion");
136        extrafields.add("ViewCodeSequence_CodeMeaning");
137
138
139        extrafields.add("SOPInstanceUID");
140        
141        String query = getQueryString(keys, rsp);
142        //System.out.println("OLD Query: "+query);
143        query = applyQueryFilter(query);
144        
145        System.out.println("NEW Query: "+query);
146
147        /** 
148         * Search results
149         * TODO: 
150         * - Get Search String Query?
151         * - Is A Network Search?
152         * - How works extrafields?
153         */
154
155        SearchDicomResult.QUERYLEVEL level = null ;
156        /*
157        if (CFindBuilder.isPatientRoot(rsp))
158        {
159            level = SearchDicomResult.QUERYLEVEL.PATIENT;
160        }
161        else if (CFindBuilder.isStudyRoot(rsp))
162        {
163            level = SearchDicomResult.QUERYLEVEL.STUDY;
164        }*/
165        DicomElement elem = keys.get(Integer.parseInt("00080052", 16));
166        String levelStr = new String(elem.getBytes());
167
168        if (levelStr.contains("PATIENT"))
169        {
170            level = SearchDicomResult.QUERYLEVEL.PATIENT;
171        }
172        else if(levelStr.contains("STUDY"))
173        {
174            level = SearchDicomResult.QUERYLEVEL.STUDY;
175        }
176        else if (levelStr.contains("SERIES"))
177        {
178            level = SearchDicomResult.QUERYLEVEL.SERIE;
179        }
180        else if (levelStr.contains("IMAGE"))
181        {
182            level = SearchDicomResult.QUERYLEVEL.IMAGE;
183        }
184        System.out.println("Charset: "+ this.keys.get(Tag.SpecificCharacterSet));
185        search = new SearchDicomResult(query,
186                 true, extrafields, level);
187
188
189
190         if (search == null)
191         {
192            //DebugManager.getInstance().debug(">> Search is null, so" +
193            //        " somethig is wrong ");
194         }
195         
196        // always return Specific Character Set
197        if (!keys.contains(Tag.SpecificCharacterSet)) {
198            this.keys.putNull(Tag.SpecificCharacterSet, VR.CS);
199            keys.putNull(Tag.SpecificCharacterSet, VR.CS);
200            this.rsp.putNull(Tag.SpecificCharacterSet, VR.CS);
201        }
202
203    }
204
205
206
207
208    private String getQueryString(DicomObject keys, DicomObject rsp)
209    {
210        String result = "";
211        try
212        {
213            CFindBuilder c = new CFindBuilder(keys, rsp);
214            result = c.getQueryString() ;
215        } catch (CFindNotSupportedException ex)
216        {
217            LoggerFactory.getLogger(FindRSP.class).error(ex.getMessage(), ex);
218        }
219
220        return result ;
221    }
222
223     private String applyQueryFilter(String normalQuery){
224        if(luke == null)
225            return normalQuery;
226       //LuceneQueryACLManager luke = new LuceneQueryACLManager(manager);
227       
228       String query = luke.produceQueryFilter(new Principal("AETitle", callingAET));
229         if(query.length() > 0 )
230             return normalQuery + query;
231               
232        return normalQuery;
233    }
234
235
236
237    /**
238     * 
239     * Verify if have a next DicomObject and set 
240     * the pointer of DicomObject with correct paraments
241     * It also apply the filter to verify if the DicomObject matches
242     * with query and if it is not search for the next DicomObject.
243     * 
244     * @return true if there is a next DicomObject
245     * @throws java.io.IOException
246     * @throws java.lang.InterruptedException
247     */
248
249    @Override
250    public boolean next() throws IOException, InterruptedException 
251    {
252        if (search!=null)
253        {
254            if (search.hasNext())
255            {
256                    //DebugManager.getInstance().debug("We have next, so get it");
257                    mwl = search.next();
258                    //if (mwl.matches(this.keys, true))
259                    //{
260
261                        // always return Specific Character Set
262                        if (!this.mwl.contains(Tag.SpecificCharacterSet))
263                            this.mwl.putNull(Tag.SpecificCharacterSet, VR.CS);
264                        this.rsp.putInt(Tag.Status, VR.US, mwl.containsAll(keys) ? Status.Pending : Status.PendingWarning);
265                        return true;
266                    //}
267            }
268
269            /** Sucess */
270            this.rsp.putInt(Tag.Status, VR.US, Status.Success);
271            /** Clean pointers */
272            this.mwl = null;
273            this.search = null;
274            return true ;
275            
276        }
277        else
278        {
279            this.rsp.putInt(Tag.Status, VR.US, Status.Cancel);
280        }
281        return false;
282    }
283    
284    /**
285     * 
286     * @return
287     */
288    @Override
289    public DicomObject getCommand() 
290    {
291        return this.rsp;
292    }
293    
294    
295    /**
296     * This method see the current DicomObject and return it
297     * @return null or DicomObject
298     */
299    @Override
300    public DicomObject getDataset() 
301    {
302        //DebugManager.getInstance().debug("Get Data Set");
303        return  this.mwl != null ? this.mwl.subSet(this.keys) : null;
304    }
305
306    @Override
307    public void cancel(Association arg0) throws IOException 
308    {
309
310        search = null ;
311        try
312        {
313            arg0.release(true);
314            
315        } catch (InterruptedException ex)
316        {
317            LoggerFactory.getLogger(FindRSP.class).error(ex.getMessage(), ex);
318        }
319    }
320
321   @Override
322    protected void finalize() throws Throwable
323   {
324
325        super.finalize();
326
327
328    }
329
330}
331