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-sdk.
005 *
006 * Dicoogle/dicoogle-sdk 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-sdk 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.sdk.datastructs;
020
021import java.io.Serializable;
022import java.net.URI;
023import java.util.HashMap;
024
025/**
026 * Simple holder class to store one hit from searches.
027 * 
028 * @author Marco
029 * @author Carlos Ferreira
030 * @author Pedro Bento
031 * modified by: Frederico Valente
032 */
033public class SearchResult implements Serializable {
034    private URI location; //a uri that allows us to fetch the result object
035    private double score; //score given by the querier
036    
037    //stores extra data, placed by specific plugins or inserted along the way
038    private HashMap<String, Object> extraData = new HashMap<>(); 
039
040    public SearchResult(URI location, double score, HashMap<String,Object> data){
041        this.location = location;
042        this.score = score;
043        
044        if(data != null)
045            this.extraData = data;
046    }
047    
048    
049    /**
050     * Gets the location of the hit
051     * @return URI pointing to dicom object
052     */
053    public URI getURI(){return location;}
054
055    
056    public Object get(String tag){
057        return extraData.get(tag);
058    }
059    
060    public void put(String tag, Object value){
061        extraData.put(tag, value);
062    }
063    
064    public <T> T getData(String extraFieldName){
065        Object ret = extraData.get(extraFieldName);
066        
067        if(ret == null) return null;
068         
069        try{
070            return (T) ret;
071        }
072        catch(ClassCastException e){
073            return null;
074        }
075    }
076    
077    /**
078     * Unlike what the name says, this does not returns the score.
079     * Unless it does. Ok, it does... which is most definitely weird given the method name.
080     * This score is a measure of *dissimilarity* 
081     * that is, a score of 0 should mean an exact hit
082     * 
083     * @return score of the result;
084     */
085    public double getScore(){return score;}
086    
087    /**
088     * Gets the extra documents fields
089     * @return the table containing the extra fields
090     */
091    public HashMap<String, Object> getExtraData(){return extraData;}
092
093    @Override
094    public String toString(){
095        return location.toString()+" "+score;
096    }
097    
098    
099    /*  Returns a tree made of hashmaps
100     * the first key is the patientName, the second the study, followed by series and image uri
101     * 
102     * todo: move the goddamned hash train to a class,
103     * just the definition of this makes me sick
104     */
105    public static HashMap<String, HashMap<String, HashMap<String, HashMap<String, SearchResult>>>> toTree(Iterable<SearchResult> results){
106        HashMap<String, HashMap<String, HashMap<String, HashMap<String, SearchResult>>>> tree = new HashMap<>();
107        
108        for(SearchResult r : results){
109            URI fileName = r.getURI();
110            String patientName = r.<String>getData("PatientName");
111            String studyUID = r.<String>getData("StudyInstanceUID");
112            String seriesUID = r.<String>getData("SeriesInstanceUID");
113            //we could have a SOPInstanceUID here but we use the search result itself as last element
114
115            if(patientName == null) patientName = "undefined PatientName";
116            else{patientName = patientName.trim();}
117            
118            if(studyUID == null) studyUID = "undefined StudyInstanceUID";
119            else{studyUID = studyUID.trim();}
120            
121            if(seriesUID == null) seriesUID = "undefined SeriesInstanceUID";
122            else{seriesUID = seriesUID.trim();}
123            
124            //check patient
125            if(tree.containsKey(patientName)){    
126                if(tree.get(patientName).containsKey(studyUID)){
127                    if(tree.get(patientName).get(studyUID).containsKey(seriesUID)){
128                        tree.get(patientName).get(studyUID).get(seriesUID).put(fileName.toString(), r);
129                    }
130                    else{
131                        HashMap<String, SearchResult> seriesResults = new HashMap<>();
132                        seriesResults.put(fileName.toString(), r);
133                        
134                        tree.get(patientName).get(studyUID).put(seriesUID, seriesResults);
135                    }
136                }
137                else{//no study
138                    HashMap<String, SearchResult> seriesResults = new HashMap<>();
139                    seriesResults.put(fileName.toString(), r);
140                
141                    HashMap<String, HashMap<String, SearchResult>> studySeries = new HashMap<>();
142                    studySeries.put(seriesUID, seriesResults);
143                
144                    tree.get(patientName).put(studyUID, studySeries);
145                }
146            }
147            else{//no patient name
148                HashMap<String, SearchResult> seriesResults = new HashMap<>();
149                seriesResults.put(fileName.toString(), r);
150                
151                HashMap<String, HashMap<String, SearchResult>> studySeries = new HashMap<>();
152                studySeries.put(seriesUID, seriesResults);
153                
154                HashMap<String, HashMap<String, HashMap<String,SearchResult>>> patientStudies = new HashMap<>();
155                patientStudies.put(studyUID, studySeries);
156                
157                tree.put(patientName, patientStudies);//add patient, study, series, image to tree
158            }
159        }
160        return tree;
161    }
162    
163}