From 9c77f4bd9f27d0c177a1fb315403a4b05e5018a7 Mon Sep 17 00:00:00 2001
From: Tim Steiner <tsteiner2@unl.edu>
Date: Fri, 14 Dec 2012 15:57:43 -0600
Subject: [PATCH] Modify MakeOfficial to also find and update any changed
 course codes.

---
 .../ApprovalActionMakeOfficialModel.php       | 24 +++++
 .../modules/courses/models/CourseModel.php    | 95 +++++++++++++++++++
 2 files changed, 119 insertions(+)

diff --git a/application/modules/courses/models/ApprovalActionMakeOfficialModel.php b/application/modules/courses/models/ApprovalActionMakeOfficialModel.php
index 87f2451c..a2a50516 100644
--- a/application/modules/courses/models/ApprovalActionMakeOfficialModel.php
+++ b/application/modules/courses/models/ApprovalActionMakeOfficialModel.php
@@ -105,6 +105,30 @@ class Courses_ApprovalActionMakeOfficialModel extends Requests_ApprovalActionMod
         Requests_RequestModel::save($requests);
         
         $courses = Courses_CourseModel::findLatestOfRequest($requests);
+        $parentCourses = Courses_CourseModel::findParentOfRequest($requests);
+        
+        // Update all references to changed course codes in other courses.
+        foreach ($requests as $request) {
+            $course = $courses[$request->getId()];
+            $parentCourse = $parentCourses[$request->getId()];
+            if (!$parentCourse) {
+                continue;
+            }
+            
+            foreach ($course->getChangedCourseCodes($parentCourse) as $change) {
+                if ($change['from']['subject'] != $change['to']['subject']) {
+                    continue;
+                }
+                Courses_CourseModel::updateCourseNumber(
+                    $change['from']['subject'],
+                    $change['from']['courseNumber'],
+                    $change['from']['courseLetter'],
+                    $change['to']['courseNumber'],
+                    $change['to']['courseLetter']
+                );
+            }
+        }
+        
         foreach ($courses as $course) {
             $course->setType('official');
         }
diff --git a/application/modules/courses/models/CourseModel.php b/application/modules/courses/models/CourseModel.php
index bd06fce7..ce627ffe 100644
--- a/application/modules/courses/models/CourseModel.php
+++ b/application/modules/courses/models/CourseModel.php
@@ -3645,5 +3645,100 @@ class Courses_CourseModel extends Unl_Model
             )
         );
     }
+    
+    public function getChangedCourseCodes(self $parentCourse = NULL)
+    {
+        if (!$parentCourse) {
+            return array();
+        }
+
+        $parentCrosslistings = array();
+        foreach ($parentCourse->getCrosslistings() as $crosslisting) {
+            $parentCrosslistings[$crosslisting['type']][$crosslisting['subject']][] = array(
+                'subject' => $crosslisting['subject'],
+                'courseNumber' => $crosslisting['courseNumber'],
+                'courseLetter' => $crosslisting['courseLetter']
+            );
+            usort($parentCrosslistings[$crosslisting['type']][$crosslisting['subject']], function($a, $b) {
+                return strcmp($a['courseNumber'] . $a['courseLetter'], $b['courseNumber'] . $b['courseLetter']);
+            });
+            ksort($parentCrosslistings[$crosslisting['type']]);
+        }
+        
+        $currentCrosslistings = array();
+        foreach ($this->getCrosslistings() as $crosslisting) {
+            $currentCrosslistings[$crosslisting['type']][$crosslisting['subject']][] = array(
+                'subject' => $crosslisting['subject'],
+                'courseNumber' => $crosslisting['courseNumber'],
+                'courseLetter' => $crosslisting['courseLetter']
+            );
+            usort($currentCrosslistings[$crosslisting['type']][$crosslisting['subject']], function($a, $b) {
+                return strcmp($a['courseNumber'] . $a['courseLetter'], $b['courseNumber'] . $b['courseLetter']);
+            });
+            ksort($currentCrosslistings[$crosslisting['type']]);
+        }
+        
+        foreach ($parentCrosslistings as $type => $p) {
+            foreach ($p as $subject => $courseNumbers) {
+                foreach ($courseNumbers as $courseNumber) {
+                    if (($key = array_search($courseNumber, $currentCrosslistings[$type][$subject])) !== FALSE) {
+                        unset($currentCrosslistings[$type][$subject][$key]);
+                    }
+                }
+            }
+        }
+        foreach ($currentCrosslistings as $type => $p) {
+            foreach ($p as $subject => $courseNumbers) {
+                foreach ($courseNumbers as $courseNumber) {
+                    if (($key = array_search($courseNumber, $parentCrosslistings[$type][$subject])) !== FALSE) {
+                        unset($parentCrosslistings[$type][$subject][$key]);
+                    }
+                }
+            }
+        }
+
+        $changes = array();
+        $map = function($fromNumbers, $toNumbers) use (&$map, &$changes) {
+            if (count($fromNumbers) == 0 || count($toNumbers) == 0) {
+                return array();
+            }
+            
+            $minDiff = 9999999;
+            $minTiebreaker = 9999999;
+            foreach ($fromNumbers as $fromKey => $fromNumber) {
+                foreach ($toNumbers as $toKey => $toNumber) {
+                    $diff = levenshtein(implode('', $fromNumber), implode('', $toNumber));
+                    $tieBreaker = abs($fromNumber['courseNumber'] - $toNumber['courseNumber']);
+                    if ($diff <= $minDiff && $tieBreaker < $minTiebreaker) {
+                        $minDiff = $diff;
+                        $minTiebreaker = $tieBreaker;
+                        $finalFromKey = $fromKey;
+                        $finalToKey = $toKey;
+                    }
+                }
+            }
+            
+            $change = array(
+                'from' => $fromNumbers[$finalFromKey],
+                'to'   => $toNumbers[$finalToKey],
+            );
+            
+            unset($fromNumbers[$finalFromKey]);
+            unset($toNumbers[$finalToKey]);
+            
+            $changes += $map($fromNumbers, $toNumbers);
+            $changes[] = $change;
+            
+            return $changes;
+        };
+        
+        foreach ($parentCrosslistings as $type => $p) {
+            foreach ($p as $subject => $courseNumbers) {
+                $map($courseNumbers, $currentCrosslistings[$type][$subject]);
+            }
+        }
+        
+        return $changes;
+    }
 }
 
-- 
GitLab