001    package org.hackystat.projectbrowser.page.dailyprojectdata.complexity;
002    
003    import java.io.Serializable;
004    import java.util.ArrayList;
005    import java.util.List;
006    import java.util.logging.Logger;
007    
008    import org.hackystat.projectbrowser.ProjectBrowserApplication;
009    import org.hackystat.projectbrowser.page.dailyprojectdata.detailspanel.DailyProjectDetailsPanel;
010    import org.hackystat.sensorbase.resource.projects.jaxb.Project;
011    import org.hackystat.utilities.stacktrace.StackTrace;
012    import org.hackystat.dailyprojectdata.resource.complexity.jaxb.FileData;
013    
014    /**
015     * Data structure for representing complexity information about a single project. 
016     * This representation includes the Project, plus the number of methods in the project with 
017     * complexity in each of five buckets: 0-10, 11-20, 21-30, 31-40, and 41+
018     * 
019     * @author Philip Johnson
020     * @author Shaoxuan Zhang
021     */
022    public class ComplexityData implements Serializable {
023    
024      /** Support serialization. */
025      private static final long serialVersionUID = 1L;
026      
027      /** The project whose data is kept in this instance. */
028      private Project project;
029      
030      /** The five buckets for this data. */
031      private List<List<FileData>> buckets = new ArrayList<List<FileData>>();
032      
033      /** The total number of entries added across all buckets. */
034      private int total = 0;
035    
036      /**
037       * Creates a new complexityData instance.  
038       * @param name The name of the Project associated with this instance. 
039       */
040      public ComplexityData(Project name) {
041        this.project = name;
042        for (int i = 0; i < 5; i++) {
043          buckets.add(new ArrayList<FileData>());
044        }
045      }
046      
047      
048      /**
049       * Adds the complexity data in this FileData instance to the appropriate buckets.
050       * @param data The FileData.
051       */
052      public void addEntry(FileData data) {
053        String methodData = data.getComplexityValues();
054        List<Integer> complexities = getComplexities(methodData);
055        for (Integer complexity : complexities) {
056          addEntry(complexity, data);
057          this.total++;
058        }
059      }
060      
061      /**
062       * Updates this ComplexityData instance with information about the number of complexitys for 
063       * a specific class. 
064       * @param complexityCount The number of complexitys. 
065       * @param data The FileData containing this complexity count.
066       */
067      public void addEntry(int complexityCount, FileData data) {
068        try {
069          if (complexityCount <= 5) {
070            buckets.get(0).add(data);
071          }
072          else if (complexityCount <= 10) {
073            buckets.get(1).add(data);
074          }
075          else if (complexityCount <= 15) {
076            buckets.get(2).add(data);
077          }
078          else if (complexityCount <= 20) {
079            buckets.get(3).add(data);
080          }
081          else {
082            buckets.get(4).add(data);
083          }
084        }
085        catch (Exception e) {
086          Logger logger = ((ProjectBrowserApplication)ProjectBrowserApplication.get()).getLogger();
087          logger.info("Error adding an entry to complexity DPD: " + StackTrace.toString(e));
088        }
089      }
090      
091      /**
092       * Returns the current value of the specified bucket. 
093       * @param bucket The bucket number, where 0 is the first one and 4 is the last one. 
094       * @return The value inside the given bucket. 
095       */
096      public int getBucketValue(int bucket) {
097        return buckets.get(bucket).size();
098      }
099      
100      /**
101       * Returns the total number of entries across all buckets. 
102       * @return The total number of entries. 
103       */
104      public int getTotal() {
105        return this.total;
106      }
107      
108      /**
109       * Returns the total number of entries across all buckets as a string. 
110       * @return The total number of entries. 
111       */
112      public String getTotalString() {
113        return String.valueOf(this.total);
114      }
115      
116      /**
117       * Returns the bucket value as a percentage of the total number of entries across all buckets.
118       * @param bucket The bucket whose percentage is to be returned.
119       * @return The bucket as a percentage.
120       */
121      public int getBucketPercentage(int bucket) {
122        if (getTotal() == 0) {
123          return 0;
124        }
125        else {
126          double percent = (double)getBucketValue(bucket) / (double)getTotal();
127          return ((int) (percent * 100));
128        }
129      }
130        
131      /**
132       * Returns the current value of the specified bucket as a string. 
133       * @param bucket The bucket number, where 0 is the first one and 4 is the last one. 
134       * @return The value inside the given bucket. 
135       */
136      public String getBucketCountString(int bucket) {
137        return String.valueOf(getBucketValue(bucket));
138      }
139      
140      /**
141       * Returns the bucket percentage as a string.
142       * @param bucket The bucket.
143       * @return Its percentage as a string.
144       */
145      public String getBucketPercentageString(int bucket) {
146        return getBucketPercentage(bucket) + "%";
147      }
148      
149     
150      /**
151       * Return the project associated with this data. 
152       * @return The project.
153       */
154      public Project getProject() {
155        return project;
156      }
157      
158      /**
159       * Returns a details panel containing information about this bucket.
160       * @param id The wicket id for this panel.
161       * @param bucket The bucket of interest. 
162       * @param isCount True if the count should be returned, false if percentage. 
163       * @return The DailyProjectDetailsPanel instance. 
164       */
165      public DailyProjectDetailsPanel getPanel(String id, int bucket, boolean isCount) {
166        DailyProjectDetailsPanel dpdPanel = 
167          new DailyProjectDetailsPanel(id, "Complexity Data", 
168              ((isCount) ? this.getBucketCountString(bucket) : this.getBucketPercentageString(bucket)));
169        dpdPanel.getModalWindow().setContent(
170            new ComplexityDetailsPanel(dpdPanel.getModalWindow().getContentId(),
171            buckets.get(bucket)));
172            
173        return dpdPanel;
174      }
175      
176    
177      /**
178       * Takes the string containing method complexities and returns them as a List of Integers.
179       * This really should go into the DPD system.  
180       * @param methodData The method data as a string. 
181       * @return The method data as a list of integers. 
182       */
183      private List<Integer> getComplexities(String methodData) {
184        List<Integer> methodComplexities = new ArrayList<Integer>();
185        try {
186          String[] numStringList = methodData.split(",");
187          for (String numString : numStringList) {
188            methodComplexities.add(Integer.parseInt(numString));
189          }
190        }
191        catch (Exception e) {
192          Logger logger = ((ProjectBrowserApplication)ProjectBrowserApplication.get()).getLogger();
193          logger.info("Failed to parse Complexity method data: " + methodData);
194        }
195        return methodComplexities;
196      }
197    }