001    package org.hackystat.dailyprojectdata.resource.codeissue;
002    
003    import java.util.Map;
004    import java.util.HashMap;
005    import java.util.Set;
006    import java.util.HashSet;
007    import javax.xml.datatype.XMLGregorianCalendar;
008    
009    import org.hackystat.sensorbase.resource.sensordata.jaxb.SensorData;
010    import org.hackystat.utilities.tstamp.Tstamp;
011    
012    /**
013     * Provides a mechanism for generating a "snapshot" for each of several tools. 
014     * The "snapshot" is the set of sensor data instances for the given tool with the 
015     * latest runtime value. 
016     * 
017     * To use this tool, create an instance, then add() each sensor data instance of interest
018     * to it. When finished, you can obtain a snapshot for any given tool, which is the set
019     * of sensor data instances associated with that tool with the latest runtime value.
020     * 
021     * @author Philip Johnson
022     *
023     */
024    public class MultiToolSnapshot {
025      
026      /** Holds a map from tool to a set containing the latest snapshot of sensor data for this tool.*/
027      private Map<String, Set<SensorData>> tool2SensorData = new HashMap<String, Set<SensorData>>();
028    
029      /**
030       * Create a MultiToolSnapshot.
031       */
032      public MultiToolSnapshot() {
033        // don't do anything here.
034      }
035      
036      /**
037       * Processes the SensorData instance, potentially adding it if its runtime is equal to or greater
038       * than the runtime associated with the stored instances of that tool.
039       * @param data The sensor data instance. 
040       */
041      public void add(SensorData data) {
042        String tool = data.getTool();
043        // If our data structure does not already have an entry for tool, make one.
044        if (tool2SensorData.get(tool) == null) {
045          tool2SensorData.put(tool, new HashSet<SensorData>());
046        }
047        
048        // If we don't have any stored sensor data for this tool, then add it and return.
049        if (tool2SensorData.get(tool).isEmpty()) {
050          tool2SensorData.get(tool).add(data);
051          return;
052        }
053        
054        // Otherwise we have stored sensor data for this tool.
055        XMLGregorianCalendar newRuntime = data.getRuntime();
056        XMLGregorianCalendar storedRuntime = getStoredRuntime(tool);
057    
058        // Case 1: new runtime equals stored runtime -> add it. 
059        if (Tstamp.equal(newRuntime, storedRuntime)) {
060          tool2SensorData.get(tool).add(data);
061        }
062        // Case 2: new runtime is more recent -> replace with it.
063        else if (Tstamp.greaterThan(newRuntime, storedRuntime)) {
064          tool2SensorData.get(tool).clear();
065          tool2SensorData.get(tool).add(data);
066        }
067        // Case 3: new runtime is older, so don't do anything.
068      }
069      
070      /**
071       * Returns the set of all Tools in this MultiToolSnapshot.
072       * @return The set of all tools.
073       */
074      public Set<String> getTools() {
075        return tool2SensorData.keySet();
076      }
077    
078      /**
079       * Returns the latest snapshot associated with the specified tool.
080       * @param tool The tool name.
081       * @return The snapshot, which could be empty.
082       */
083      public Set<SensorData> getSensorData(String tool) {
084        Set<SensorData> snapshot = tool2SensorData.get(tool);
085        return (snapshot == null) ? new HashSet<SensorData>() : snapshot;
086      }
087      
088      
089      
090      /**
091       * Returns the stored runtime associated with Tool.
092       * @param tool The tool whose stored runtime should be returned.
093       * @return The stored runtime, or null if no entries in the map.
094       */
095      private XMLGregorianCalendar getStoredRuntime(String tool) {
096        Set<SensorData> dataSet = tool2SensorData.get(tool);
097        for (SensorData data : dataSet) {
098          return data.getRuntime();
099        }
100        return null;
101      }
102    
103    }