001    /*
002     * Sonar, open source software quality management tool.
003     * Copyright (C) 2008-2011 SonarSource
004     * mailto:contact AT sonarsource DOT com
005     *
006     * Sonar is free software; you can redistribute it and/or
007     * modify it under the terms of the GNU Lesser General Public
008     * License as published by the Free Software Foundation; either
009     * version 3 of the License, or (at your option) any later version.
010     *
011     * Sonar 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 GNU
014     * Lesser General Public License for more details.
015     *
016     * You should have received a copy of the GNU Lesser General Public
017     * License along with Sonar; if not, write to the Free Software
018     * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
019     */
020    
021    package org.sonar.graph;
022    
023    import java.util.ArrayList;
024    import java.util.Collections;
025    import java.util.Iterator;
026    import java.util.List;
027    import java.util.Set;
028    
029    import com.google.common.collect.HashMultiset;
030    import com.google.common.collect.Multiset;
031    
032    /**
033     * Note: this class has a natural ordering that is inconsistent with equals
034     */
035    public final class FeedbackCycle implements Iterable<FeedbackEdge>, Comparable<FeedbackCycle> {
036    
037      private List<FeedbackEdge> orderedFeedbackEdges;
038      private int totalOccurrencesOfEdgesInCycle;
039      private final Cycle cycle;
040    
041      private FeedbackCycle(Cycle cycle) {
042        orderedFeedbackEdges = new ArrayList<FeedbackEdge>();
043        totalOccurrencesOfEdgesInCycle = 0;
044        this.cycle = cycle;
045      }
046    
047      private void add(FeedbackEdge feedbackEdge) {
048        orderedFeedbackEdges.add(feedbackEdge);
049      }
050    
051      public static List<FeedbackCycle> buildFeedbackCycles(Set<Cycle> cycles) {
052        Multiset<Edge> edgesBag = createBagWithAllEdgesOfCycles(cycles);
053    
054        List<FeedbackCycle> feedbackCycles = new ArrayList<FeedbackCycle>();
055        for (Cycle cycle : cycles) {
056          FeedbackCycle feedbackCycle = new FeedbackCycle(cycle);
057          int totalOccurrences = 0;
058          for (Edge edge : cycle.getEdges()) {
059            FeedbackEdge feedbackEdge = new FeedbackEdge(edge, edgesBag.count(edge));
060            feedbackCycle.add(feedbackEdge);
061            totalOccurrences += feedbackEdge.getOccurences();
062          }
063          feedbackCycle.setTotalOccurrencesOfEdgesInCycle(totalOccurrences);
064          Collections.sort(feedbackCycle.orderedFeedbackEdges);
065          feedbackCycles.add(feedbackCycle);
066        }
067        Collections.sort(feedbackCycles);
068    
069        return feedbackCycles;
070      }
071    
072      private static Multiset<Edge> createBagWithAllEdgesOfCycles(Set<Cycle> cycles) {
073        Multiset<Edge> edgesBag = HashMultiset.create();
074        for (Cycle cycle : cycles) {
075          for (Edge edge : cycle.getEdges()) {
076            edgesBag.add(edge);
077          }
078        }
079        return edgesBag;
080      }
081    
082      private void setTotalOccurrencesOfEdgesInCycle(int totalOccurrencesOfEdgesInCycle) {
083        this.totalOccurrencesOfEdgesInCycle = totalOccurrencesOfEdgesInCycle;
084      }
085    
086      public int getTotalOccurrencesOfEdgesInCycle() {
087        return totalOccurrencesOfEdgesInCycle;
088      }
089    
090      public Iterator<FeedbackEdge> iterator() {
091        return orderedFeedbackEdges.iterator();
092      }
093    
094      public int compareTo(FeedbackCycle feedbackCycle) {
095        if (getTotalOccurrencesOfEdgesInCycle() < feedbackCycle.getTotalOccurrencesOfEdgesInCycle()) {//NOSONAR this class has a natural ordering that is inconsistent with equals
096          return -1;
097        }
098        if (getTotalOccurrencesOfEdgesInCycle() == feedbackCycle.getTotalOccurrencesOfEdgesInCycle()) {
099          if (cycle.size() == feedbackCycle.cycle.size()) {
100            return orderedFeedbackEdges.get(0).compareTo(feedbackCycle.orderedFeedbackEdges.get(0));
101          }
102          return cycle.size() - feedbackCycle.cycle.size();
103        }
104        return 1;
105      }
106    
107      public Cycle getCycle() {
108        return cycle;
109      }
110    }