--- /dev/null
+package no.uio.ifi.refaktor.analyze.analyzers;
+
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.LinkedList;
+
+import no.uio.ifi.refaktor.analyze.CollectorManager;
+import no.uio.ifi.refaktor.analyze.checkers.LegalStatementsChecker;
+import no.uio.ifi.refaktor.analyze.collectors.PrefixesCollector;
+import no.uio.ifi.refaktor.analyze.collectors.UnfixesCollector;
+import no.uio.ifi.refaktor.analyze.exceptions.NoTargetFoundException;
+import no.uio.ifi.refaktor.analyze.exceptions.RefaktorAnalyzerException;
+import no.uio.ifi.refaktor.change.changers.ExtractAndMoveMethodChanger;
+import no.uio.ifi.refaktor.prefix.Prefix;
+import no.uio.ifi.refaktor.prefix.PrefixSet;
+import no.uio.ifi.refaktor.textselection.CompilationUnitTextSelection;
+
+import org.eclipse.jdt.core.dom.IVariableBinding;
+
+//TODO: rewrite docs
+/**
+ * A property extractor that collects all the expression prefixes within a selection
+ * (see {@link PrefixesCollector}) that forms the base for calculating the
+ * candidates for the move refactoring, and also the unfixes
+ * that are non-candidates for the move refactoring.
+ *
+ * The set of prefixes that are not enclosing any unfixes is put in the set of safe prefixes.
+ * This set is used by an Extract and Move Method refactoring to find a suitable target
+ * for the Move Method.
+ *
+ * The class is typically used by the {@link ExtractAndMoveMethodChanger}.
+ */
+public class ExtractAndMoveMethodAnalyzer implements Analyzer {
+
+ private final CompilationUnitTextSelection selection;
+ private final PrefixesCollector prefixesCollector;
+ private final UnfixesCollector unfixesCollector;
+
+ public ExtractAndMoveMethodAnalyzer(CompilationUnitTextSelection selection) {
+ this.selection = selection;
+ prefixesCollector = new PrefixesCollector(selection);
+ unfixesCollector = new UnfixesCollector(selection);
+ }
+
+ public PrefixSet calculateSafePrefixes() {
+ PrefixSet safePrefixes = prefixesCollector.getPrefixes().minusEnclosedPrefixesFrom(unfixesCollector.getUnfixes());
+ removeUnusablePrefixes(safePrefixes);
+ return safePrefixes;
+ }
+
+ private void removeUnusablePrefixes(PrefixSet safePrefixes) {
+ for (Iterator<Prefix> iter = safePrefixes.iterator(); iter.hasNext();) {
+ if (prefixHasSimpleExpressionAndOnlyOneOccurrence(iter.next()))
+ iter.remove();
+ }
+ }
+
+ private boolean prefixHasSimpleExpressionAndOnlyOneOccurrence(Prefix prefix) {
+ return prefix.getNumberOfSegments() == 1 && prefix.getCount() == 1;
+ }
+
+ protected PrefixSet getPrefixes() {
+ return prefixesCollector.getPrefixes();
+ }
+
+ public PrefixSet getUnfixes() {
+ return unfixesCollector.getUnfixes();
+ }
+
+ public void checkPreconditions() throws RefaktorAnalyzerException {
+ SelectionValidator.checkIfSelectionIsValid(selection);
+ analyze();
+ checkIfUsefulTargetFound();
+ }
+
+ private void checkIfUsefulTargetFound() {
+ if (!hasUsefulResults())
+ throw new NoTargetFoundException();
+ }
+
+ public boolean hasUsefulResults() {
+ return !calculateSafePrefixes().isEmpty();
+ }
+
+ @Override
+ public void analyze() throws RefaktorAnalyzerException {
+ LegalStatementsChecker legalStatementsChecker = new LegalStatementsChecker(selection);
+ if (legalStatementsChecker.allStatementsAreLegal())
+ CollectorManager.collectProperties(selection, prefixesCollector, unfixesCollector);
+ }
+
+ public IVariableBinding calculateOriginalTarget() {
+ return calculateMostFrequentPrefix().getVariableBindingOfFirstExpression();
+ }
+
+ public Prefix calculateMostFrequentPrefix() {
+ LinkedList<Prefix> listOfSafePrefixes = calculateListOfSafePrefixes();
+ sortAscendingByCountAndLength(listOfSafePrefixes);
+ return listOfSafePrefixes.getLast();
+ }
+
+ private LinkedList<Prefix> calculateListOfSafePrefixes() {
+ return calculateSafePrefixes().toList();
+ }
+
+ private void sortAscendingByCountAndLength(LinkedList<Prefix> values) {
+ Collections.sort(values, new Comparator<Prefix>() {
+ @Override
+ public int compare(Prefix p1, Prefix p2) {
+ if (p1.getCount() > p2.getCount()) {
+ return 1;
+ } else if (p1.getCount() < p2.getCount()) {
+ return -1;
+ } else if (p1.length() > p2.length()) {
+ return 1;
+ } else if (p1.length() < p2.length()) {
+ return -1;
+ }
+ return 0;
+ }
+ });
+ }
+}