From 9ce03fcaa1acd36922314ce2d7b654842dbef4f9 Mon Sep 17 00:00:00 2001
From: Tom Vahlman <tom@dsv.su.se>
Date: Sat, 25 Feb 2012 21:47:03 +0100
Subject: [PATCH] Points, total availability (bachelor + master) and type of
 project class must be considered when sorting a list of Pair representing
 matches.

---
 .../scipro/match/GreedyMatchingAlgorithm.java | 81 +++++++++++++++++--
 .../match/TestGreedyMatchingAlgorithm.java    |  6 +-
 2 files changed, 77 insertions(+), 10 deletions(-)

diff --git a/src/main/java/se/su/dsv/scipro/match/GreedyMatchingAlgorithm.java b/src/main/java/se/su/dsv/scipro/match/GreedyMatchingAlgorithm.java
index fd12006d0a..754c16cef5 100644
--- a/src/main/java/se/su/dsv/scipro/match/GreedyMatchingAlgorithm.java
+++ b/src/main/java/se/su/dsv/scipro/match/GreedyMatchingAlgorithm.java
@@ -20,7 +20,14 @@ public class GreedyMatchingAlgorithm implements MatchingAlgorithm {
 
 	private Logger logger = Logger.getLogger(GreedyMatchingAlgorithm.class);
 	private Weights weights;
-	
+
+    /**
+     * Match project ideas with supervisors (based on availability) and returns the best match.
+     * @param supervisorAvailability   a list of the Availability instances
+     * @param unmatchedProjectIdeas  a list of unmatched project ideas
+     * @param weights the weights that is used when counting points
+     * @return Result
+     */
 	@Override
 	public Result match(List<Availability> supervisorAvailability, List<ProjectIdea> unmatchedProjectIdeas, Weights weights) {
         this.weights = weights;
@@ -30,14 +37,17 @@ public class GreedyMatchingAlgorithm implements MatchingAlgorithm {
         while(!unmatchedProjectIdeas.isEmpty()) {
             pairList.clear();
             matchProjectIdeas(unmatchedProjectIdeas, supervisorAvailability, pairList);      
-            Collections.sort(pairList);
+            
             if(!pairList.isEmpty()) {
+                Collections.sort(pairList);
+                calculateTotalAvailability(pairList);
                 Pair foundPair = pairList.get(0);
                 for(Availability availability : supervisorAvailability) {
-                    if(availability.getSupervisor().equals(foundPair.getMatch().getSupervisor())) {
+                    if(availability.getSupervisor().equals(foundPair.getMatch().getSupervisor()) &&
+                            availability.getProjectClass().equals(foundPair.getAvailability().getProjectClass())) {
                         if(availability.getNumCapable() > availability.getNumMatched()) {
                             availability.setNumMatched(availability.getNumMatched() + 1);
-                            matchList.add(foundPair.getMatch());
+                                matchList.add(foundPair.getMatch());
                         }
                     }
                 }
@@ -178,7 +188,7 @@ public class GreedyMatchingAlgorithm implements MatchingAlgorithm {
 				&& supervisor.equals(projectIdea.getPreferredSupervisor())) {
 			points += weights.getPreferredSupervisorPoints();
 		}
-		
+
 		for (Keyword projectIdeaKeyword : projectIdea.getKeywords().getAll()) {
 			for (Keyword supervisorKeyword : supervisor.getKeywords().getFiltered(projectIdeaKeyword.getType())) {
 				if (projectIdeaKeyword.equals(supervisorKeyword) && !projectIdeaKeyword.isDeleted() && !supervisorKeyword.isDeleted()) {
@@ -190,10 +200,39 @@ public class GreedyMatchingAlgorithm implements MatchingAlgorithm {
 		match.setPoints(points);
 		return match;
 	}
+
+
+    /**
+     * Calculates total availability for each supervisor, i.e. the  Availability#getAvailability (int) for master
+     * is added to Availability#getAvailability (int) for bachelor for each supervisor, this total availability is considered when
+     * matching project ideas to supervisors
+     * @param pairList all the matches that is produced, represented as instances of the class Pair
+     * @return
+     */
+    private void calculateTotalAvailability(List<Pair> pairList) {
+        for(Pair ourMatch : pairList) {
+            for(Pair pair : pairList) {
+               if(ourMatch.getTotalAvailability() == 0 &&
+                       ourMatch.getAvailability().getSupervisor().equals(pair.getAvailability().getSupervisor()) &&
+                            !ourMatch.getAvailability().getProjectClass().equals(pair.getAvailability().getProjectClass())) {
+                    int totalAvailability = ourMatch.getAvailability().getAvailability() + pair.getAvailability().getAvailability();
+                    ourMatch.setTotalAvailability(totalAvailability);
+                    pair.setTotalAvailability(totalAvailability);
+                    break;
+               }
+            }
+        }
+        for(Pair ourMatch : pairList) {    // we must set total availability for supervisors that only can handle one type of project class, i.e. master or bachelor
+            if(ourMatch.getTotalAvailability() == 0) {
+                ourMatch.setTotalAvailability(ourMatch.getAvailability().getAvailability());
+            }
+        }
+    }
 		
 	private class Pair implements Comparable<Pair> {
 		private Match match;
 		private Availability availability;
+        private int totalAvailability;
 		
 		public Pair(Match match, Availability availability
         ) {
@@ -209,14 +248,42 @@ public class GreedyMatchingAlgorithm implements MatchingAlgorithm {
 			return availability;
 		}
 
+        public int getTotalAvailability() {
+            return totalAvailability;
+        }
+
+        public void setTotalAvailability(int totalAvailability) {
+            this.totalAvailability = totalAvailability;
+        }
+
+        /**
+         * Is used to sort the Pairs in an order where the Pair at the top of the list will be chosen.
+         * @param otherPair the pair we should compare with
+         * @return int determines if one Pair is more "important" than another Pair.
+         */
         @Override
         public int compareTo(Pair otherPair) {
             if(match.getPoints() > otherPair.getMatch().getPoints()) {
                 return -1;
             } else if(otherPair.getMatch().getPoints() > match.getPoints()) {
                 return 1;
-            } else {
-                return availability.compareTo(otherPair.getAvailability());
+            } else {  // if the points are the same
+                if(totalAvailability > otherPair.getTotalAvailability()) {  // does we have more "slots" than the other Pair
+                    return -1;
+                } else if(otherPair.getTotalAvailability() > totalAvailability) {
+                    return 1;
+                } else {     // the points and the slots are equal, we must now sort on Project Class because a master supervisor can supervise
+                    // both a master project idea and a bachelor project idea, the "best" match however is if a master supervisor supervises a master project idea...
+                    if(match.getProjectIdea().getProjectClass().equals(availability.getProjectClass()) &&
+                            !otherPair.getMatch().getProjectIdea().getProjectClass().equals(otherPair.getAvailability().getProjectClass())) {
+                        return -1;
+                    } else  if(!match.getProjectIdea().getProjectClass().equals(availability.getProjectClass()) &&
+                            otherPair.getMatch().getProjectIdea().getProjectClass().equals(otherPair.getAvailability().getProjectClass())) {
+                        return 1;
+                    } else {   // the supervisor can only one type of project class
+                        return 0;
+                    }
+                }
             }
         }
         
diff --git a/src/test/java/se/su/dsv/scipro/match/TestGreedyMatchingAlgorithm.java b/src/test/java/se/su/dsv/scipro/match/TestGreedyMatchingAlgorithm.java
index 0c177e8875..541f700bc2 100644
--- a/src/test/java/se/su/dsv/scipro/match/TestGreedyMatchingAlgorithm.java
+++ b/src/test/java/se/su/dsv/scipro/match/TestGreedyMatchingAlgorithm.java
@@ -98,9 +98,9 @@ public class TestGreedyMatchingAlgorithm {
 
     private void createWeights() {
         weights = new Weights();
-        weights.setKeywordPoints(3);                // "Word" (including "Unit"??)
-        weights.setResearchAreaPoints(10);          // "Area"
-        weights.setPreferredSupervisorPoints(15);
+        weights.setKeywordPoints(3);                // "Word" + "Unit"??
+        weights.setResearchAreaPoints(5);          // "Area"
+        weights.setPreferredSupervisorPoints(10);
     }
 
     private void  setUpKeyWordTypes() {