Skip to content
Snippets Groups Projects
Select Git revision
  • 4d7faa9e3921b7fdfd97e876d44827deb4a74b2b
  • main default protected
2 results

main.py

Blame
  • Forked from SOFT Core / SOFT 161 and 162 / Quizzer
    Source project has a limited visibility.
    CourseModel.php 107.51 KiB
    <?php
    
    require_once ('Unl/Model.php');
    
    class Courses_CourseModel extends Unl_Model
    {
        static protected $_colleges = array();
        static protected $_collegeNames = array();
        static protected $_departments = array();
        static protected $_hierarchy = array();
    
    	static protected $_outcomeShortNames = array(
            'SLO1'  => 'writing',
            'SLO2'  => 'communication',
            'SLO3'  => 'mathematicalReasoning',
            'SLO4'  => 'scientificReasoning',
            'SLO5'  => 'historicalPerspective',
            'SLO6'  => 'humanBehavior',
            'SLO7'  => 'artisticSignificance',
            'SLO8'  => 'civics',
            'SLO9'  => 'humanDiversity',
            'SLO10' => 'production'
        );
    
        static protected $_outcomeDescriptions = array(
            'SLO1'  => 'Write texts, in various forms, with an identified purpose, that respond to specific audience needs, incorporate research or existing knowledge, and use applicable documentation and appropriate conventions of format and structure.',
            'SLO2'  => 'Demonstrate communication competence in one or more of the following ways: (a) by making oral presentations with supporting materials, (b) by leading and participating in problem-solving teams, (c) by employing a repertoire of communication skills for developing and maintaining professional and personal relationships, or (d) by creating and interpreting visual information.',
            'SLO3'  => 'Use mathematical, computational, statistical, or formal reasoning (including reasoning based on principles of logic) to solve problems, draw inferences, and determine reasonableness.',
            'SLO4'  => 'Use scientific methods and knowledge of the natural and physical world to address problems through inquiry, interpretation, analysis, and the making of inferences from data, to determine whether conclusions or solutions are reasonable.',
            'SLO5'  => 'Use knowledge, historical perspectives, analysis, interpretation, critical evaluation, and the standards of evidence appropriate to the humanities to address problems and issues.',
            'SLO6'  => 'Use knowledge, theories, methods, and historical perspectives appropriate to the social sciences to understand and evaluate human behavior.',
            'SLO7'  => 'Use knowledge, theories, or methods appropriate to the arts to understand their context and significance.',
            'SLO8'  => 'Explain ethical principles, civics, and stewardship, and their importance to society.',
            'SLO9'  => 'Exhibit global awareness or knowledge of human diversity through analysis of an issue.',
            'SLO10' => 'Generate a creative or scholarly product that requires broad knowledge, appropriate technical proficiency, information collection, synthesis, interpretation, presentation, and reflection.'
        );
    
        static protected $_reinforcementNames = array(
            'writing'                  => 'Writing',
            'oralCommunication'        => 'Oral Communication',
            'visualLiteracy'           => 'Visual Literacy',
            'historicalPerspectives'   => 'Historical Perspectives',
            'mathematicsAndStatistics' => 'Mathematics and Statistics',
            'criticalThinking'         => 'Critical Thinking',
            'teamwork'                 => 'Teamwork',
            'problemSolving'           => 'Problem Solving',
            'ethics'                   => 'Ethics',
            'civics'                   => 'Civics',
            'socialResponsibilities'   => 'Social Responsibilities',
            'globalAwareness'          => 'Global Awareness',
            'humanDiversity'           => 'Human Diversity'
        );
    
        static protected $_activityMap;
    
        const CREDIT_TYPE_SINGLE       = 1;
        const CREDIT_TYPE_RANGE_MIN    = 2;
        const CREDIT_TYPE_RANGE_MAX    = 3;
        const CREDIT_TYPE_SEMESTER_MAX = 4;
        const CREDIT_TYPE_DEGREE_MAX   = 5;
    
    	static public function find($id)
    	{
    		$db = Zend_Registry::get('db');
    		$select = new Zend_Db_Select($db);
    
    		$select->from(array('a' => 'creqAssets'));
    		$select->join(array('g' => 'creqCourseGenerations'), 'a.assetId = g.assetId');
    		$select->join(array('d' => 'creqCourseDetails'), 'g.courseGenerationId = d.generation');
    
    		if (Unl_Util::isArray($id)) {
    			if (count($id) == 0) {
    				return new Unl_Model_Collection(__CLASS__);
    			}
    			$select->where('courseGenerationId IN(?)', $id);
    		} else {
    			$select->where('courseGenerationId = ?', $id);
    		}
    
    		$records = $select->query()->fetchAll();
    		$courseIds = array();
    		$courses = array();
    		foreach ($records as $record) {
    			$record['deliveryMethods'] = explode(',', $record['deliveryMethods']);
                if ($record['termsOffered'] == '') {
                    $record['termsOffered'] = array();
                } else {
                    $record['termsOffered'] = explode(',', $record['termsOffered']);
                }
                $record['campuses'] = explode(',', $record['campuses']);
                $record['activities'] = array();
                $record['credits'] = array();
                $record['crosslistings'] = array();
                $record['aceReinforcements'] = array();
                $record['aceOutcomes'] = array();
    			$courseId = $record['courseGenerationId'];
    			$courseIds[] = $courseId;
    			$courses[$courseId] = $record;
    		}
    
    
    		// ACE Outcomes
            $select = new Zend_Db_Select($db);
            $select->from(array('a' => 'creqCourseAceOutcomes'));
            $select->where('a.generation IN(?)', $courseIds);
    
            $records = $select->query()->fetchAll();
            foreach($records as $record) {
                $courseId = $record['generation'];
                $aceOutcomeId = $record['courseAceOutcomeId'];
                $courses[$courseId]['aceOutcomes'][$aceOutcomeId] = $record;
            }
    
            // ACE Reinforcements
            $select = new Zend_Db_Select($db);
            $select->from(array('a' => 'creqCourseAceReinforcements'));
            $select->where('a.generation IN(?)', $courseIds);
    
            $records = $select->query()->fetchAll();
            foreach($records as $record) {
                $courseId = $record['generation'];
                $aceReinforcementId = $record['courseAceReinforcementId'];
                $courses[$courseId]['aceReinforcements'][$aceReinforcementId] = $record;
            }
    
            // Activities
            $select = new Zend_Db_Select($db);
            $select->from(array('a' => 'creqCourseActivities'));
            $select->where('a.generation IN(?)', $courseIds);
    
            $records = $select->query()->fetchAll();
            foreach($records as $record) {
                $courseId = $record['generation'];
                $activityId = $record['courseActivityId'];
                $courses[$courseId]['activities'][$activityId] = $record;
            }
    
            // Credits
            $select = new Zend_Db_Select($db);
            $select->from(array('c' => 'creqCourseCredits'));
            $select->join(array('t' => 'creqCreditTypes'), 'c.type = t.creditTypeId', array('description'));
            $select->where('c.generation IN(?)', $courseIds);
    
            $records = $select->query()->fetchAll();
            foreach($records as $record) {
                $courseId = $record['generation'];
                $creditId = $record['courseCreditId'];
                $courses[$courseId]['credits'][$creditId] = $record;
            }
    
            // Crosslistings
            $select = new Zend_Db_Select($db);
            $select->from(array('x' => 'creqCourseCrosslistings'), array('courseCrosslistingId', 'generation', 'type'));
            $select->join(array('c' => 'creqCourseCodes'), 'x.courseCode = c.courseCodeId');
            $select->joinLeft(array('g' => 'creqCourseCodeGroups'), 'c.courseCodeId = g.courseCode', array('courseCodeGroupId'));
            $select->joinLeft(array('u' => 'creqCourseGroups'), 'g.group = u.courseGroupId', array('courseGroup' => 'name'));
            $select->join(array('s' => 'creqSubjects'), 'c.subject = s.name', array());
            $select->join(array('d' => 'creqDepartments'), 's.department = d.departmentId', array('department' => 'name'));
            $select->join(array('cl' => 'creqColleges'), 'd.college = cl.collegeId', array('college' => 'name', 'collegeLong' => 'description'));
            $select->where('x.generation IN(?)', $courseIds);
    
            $records = $select->query()->fetchAll();
            foreach($records as $record) {
                $courseId = $record['generation'];
                $crosslistingId = $record['courseCrosslistingId'];
                $groups = (array)$courses[$courseId]['crosslistings'][$crosslistingId]['courseGroups'];
                if ($record['courseGroup']) {
                    $groups[$record['courseCodeGroupId']] = $record['courseGroup'];
                }
                $record['courseGroups'] = $groups;
                unset($record['courseGroup']);
                $courses[$courseId]['crosslistings'][$crosslistingId] = $record;
            }
    
            // ES Designations
            $select = new Zend_Db_Select($db);
            $select->from(array('x' => 'creqCourseCrosslistings'), array('courseCrosslistingId', 'generation', 'type'));
            $select->join(array('e' => 'creqCourseEsDesignations'), 'x.courseCode = e.courseCode');
            $select->where('x.generation IN(?)', $courseIds);
    
            $records = $select->query()->fetchAll();
            foreach($records as $record) {
                $courseId = $record['generation'];
                $esDesignationId = $record['courseEsDesignationId'];
                $courses[$courseId]['esDesignations'][$esDesignationId] = $record;
            }
    
    
            // Grad Tie-in
            $select = new Zend_Db_Select($db);
            $select->from(array('t' => 'creqCourseGradTieIns'));
            $select->where('t.generation IN(?)', $courseIds);
    
            $records = $select->query()->fetchAll();
            foreach($records as $record) {
                $courseId = $record['generation'];
                $courses[$courseId]['gradTieIn'] = $record;
            }
    
    		$objects = new Unl_Model_Collection(__CLASS__);
    		foreach ($courses as $course) {
    			$object = Unl_Model_Registry::getInstance()->getOrAdd(new self($course));
    			$object->_setClean();
    			$objectId = $object->getId();
    			$objects[$objectId] = $object;
    		}
    
    		if (Unl_Util::isArray($id)) {
    			return $objects;
    		} else {
    			return $objects[$id];
    		}
    	}
    
        static public function fetchNew()
        {
            $data = array(
                'assetId'      => null,
                'creationTime' => null,
                'modifiedTime' => null,
    
                'courseGenerationId' => null,
                'parent'             => null,
                'course'             => null,
                'request'            => null,
                'type'               => 'proposed',
                'removed'            => 'no',
    
                'courseDetailId'    => null,
                'title'             => null,
                'gradingType'       => null,
                'dfRemoval'         => null,
                'campuses'          => array('UNL'),
                'deliveryMethods'   => array('Classroom'),
                'termsOffered'      => array('Fall', 'Spring', 'Summer'),
                'effectiveSemester' => null,
                'finalSemester'     => null,
                'prerequisite'      => '',
                'notes'             => '',
                'description'       => '',
    
                'activities'        => array(),
                'credits'           => array(),
                'crosslistings'     => array(),
                'esDesignations'    => array(),
                'gradTieIn'         => null,
    
                'aceReinforcements' => array(),
                'aceOutcomes'       => array()
        	);
    
            $new = new self($data);
            return $new;
        }
    
    	static public function findParentOfRequest($request)
    	{
    		$db = Zend_Registry::get('db');
    
    		if (Unl_Util::isArray($request)) {
    			if (count($request) == 0) {
    				return new Unl_Model_Collection(__CLASS__);
    			}
    			$requestId = array();
    			foreach ($request as $aRequest) {
    				$requestId[] = $aRequest->getId();
    			}
    		} else {
    			$requestId = $request->getId();
    		}
    
            $select = new Zend_Db_Select($db);
            $select->from(array('g' => 'creqCourseGenerations'), array('request'));
            $select->join(array('p' => 'creqCourseGenerations'), 'g.parent = p.courseGenerationId', array('courseGenerationId'));
            $select->where('p.request != g.request OR p.request IS NULL');
            $select->where('p.type = ?', 'official');
            if (Unl_Util::isArray($request)) {
                $select->where('g.request IN(?)', $requestId);
            } else {
                $select->where('g.request = ?', $requestId);
            }
    
            $records = $select->query()->fetchAll();
            $courseIds = array();
            foreach ($records as $record) {
            	$rId = $record['request'];
                $courseIds[$rId] = $record['courseGenerationId'];
            }
    
            self::find($courseIds);
    
    		if (Unl_Util::isArray($requestId)) {
                $rv = array();
    	        foreach ($requestId as $rId) {
    	        	$rv[$rId] = Unl_Model_Registry::getInstance()->get(__CLASS__, $courseIds[$rId]);
    	        }
    	        return $rv;
    		} else {
    			return Unl_Model_Registry::getInstance()->get(__CLASS__, $courseIds[$requestId]);
    		}
    	}
    
    	static public function findLatestOfRequest($request)
    	{
    		/**
             * TODO:
             * Make sure that if two of the requests given are on subsequent generations,
             * that we can get the latest for EACH and not just the later one.
             */
    
            $db = Zend_Registry::get('db');
    
            if (Unl_Util::isArray($request)) {
            	if (count($request) == 0) {
            		return new Unl_Model_Collection(__CLASS__);
            	}
                $requestId = array();
                foreach ($request as $aRequest) {
                    $requestId[] = $aRequest->getId();
                }
            } else {
                $requestId = $request->getId();
            }
    
            $select = new Zend_Db_Select($db);
            $select->from(array('g' => 'creqCourseGenerations'), array('parent', 'request'));
            if (Unl_Util::isArray($request)) {
                $select->where('g.request IN(?)', $requestId);
            } else {
                $select->where('g.request = ?', $requestId);
            }
    
            $records = $select->query()->fetchAll();
            $parentIds = array();
            foreach ($records as $record) {
            	if (!Unl_Util::isArray($parentIds[$record['request']])) {
            		$parentIds[$record['request']] = array();
            	}
                if (!$record['parent']) {
                    continue;
                }
                $parentIds[$record['request']][] = $record['parent'];
            }
    
            $select = new Zend_Db_Select($db);
            $select->from(array('g' => 'creqCourseGenerations'), array('courseGenerationId', 'request'));
            $whereOrs = array();
            foreach ($parentIds as $rId => $pIds) {
                $whereOr = $db->quoteInto('g.request = ? ', $rId);
                if (count($pIds) > 0) {
                    $whereOr .= $db->quoteInto('AND g.courseGenerationId NOT IN(?)', $pIds);
                }
                $whereOrs[] = $whereOr;
            }
            $whereOrs = '(' . implode(') OR (', $whereOrs) . ')';
            $select->where($whereOrs);
            if (Unl_Util::isArray($request)) {
                $select->where('g.request IN(?)', $requestId);
            } else {
                $select->where('g.request = ?', $requestId);
            }
    
            $records = $select->query()->fetchAll();
            $courseIds = array();
            foreach ($records as $record) {
                $rId = $record['request'];
                $courseIds[$rId] = $record['courseGenerationId'];
            }
    
            self::find($courseIds);
    
            if (Unl_Util::isArray($requestId)) {
                $rv = new Unl_Model_Collection(__CLASS__);
                foreach ($requestId as $rId) {
                    $rv[$rId] = Unl_Model_Registry::getInstance()->get(__CLASS__, $courseIds[$rId]);
                }
                return $rv;
            } else {
                return Unl_Model_Registry::getInstance()->get(__CLASS__, $courseIds[$requestId]);
            }
    	}
    
    	static public function findByCourseCode($subject, $courseNumber, $courseLetter = '')
    	{
    		if (!$courseLetter) {
    			$courseLetter = '';
    		}
    
    		$db = Zend_Registry::get('db');
    
    		$select = new Zend_Db_Select($db);
    		$select->from(array('c' => 'creqCourseCodes'), array());
    		$select->join(array('x' => 'creqCourseCrosslistings'), 'c.courseCodeId = x.courseCode', array());
    		$select->join(array('g' => 'creqCourseGenerations'), 'x.generation = g.courseGenerationId', array('courseGenerationId'));
    		$select->join(array('p' => 'creqCourses'), 'g.courseGenerationId = p.currentGeneration', array());
    		$select->where('g.removed = "no"');
    		$select->where('c.subject = ?', $subject);
    		$select->where('c.courseNumber = ?', $courseNumber);
            $select->where('c.courseLetter = ?', $courseLetter);
    
    		$records = $select->query()->fetchAll();
    		if (count($records) == 0) {
    			return null;
    		}
    		$generationId = $records[0]['courseGenerationId'];
    		return self::find($generationId);
    	}
    
    	static public function findByCourseId($courseId)
    	{
    		$db = Zend_Registry::get('db');
    
    		$select = new Zend_Db_Select($db);
    		$select->from(array('g' => 'creqCourseGenerations'), array('courseGenerationId'));
    		$select->join(array('c' => 'creqCourses'), 'g.courseGenerationId = c.currentGeneration', array());
    		if (Unl_Util::isArray($courseId)) {
    		    $select->where('c.courseId IN (?)', $courseId);
    		} else {
                $select->where('c.courseId = ?', $courseId);
    		}
    
    		$records = $select->query()->fetchAll();
    		if (!Unl_Util::isArray($courseId)) {
    		    if (count($records) == 0) {
                    return null;
    		    }
                $generationId = $records[0]['courseGenerationId'];
    		} else {
    		    $generationId = array();
    		    foreach ($records as $record) {
    		        $generationId[] = $record['courseGenerationId'];
    		    }
    		}
    		
    		$models = self::find($generationId);
    		
    		if (!Unl_Util::isArray($courseId)) {
    		    return $models;
    		}
    		
    		$indexedModels = new Unl_Model_Collection(__CLASS__);
    		foreach ($models as $model) {
    		    $indexedModels[$model->getCourseId()] = $model;
    		}
    		
    		return $indexedModels;
    	}
    
    	static public function findActiveRequestByCourseCode($subject, $courseNumber, $courseLetter = '')
    	{
            $db = Zend_Registry::get('db');
            if (!$courseLetter) {
            	$courseLetter = '';
            }
    
            /*
            $select = new Zend_Db_Select($db);
            $select->from(array('c' => 'creqCourseCodes'), array());
            $select->join(array('x' => 'creqCourseCrosslistings'), 'c.courseCodeId = x.courseCode', array());
            $select->join(array('g' => 'creqCourseGenerations'), 'x.generation = g.courseGenerationId', array());
            $select->join(array('r' => 'creqRequests'), 'g.request = r.requestId', array('requestId'));
            $select->where('c.subject = ?', $subject);
            $select->where('c.courseNumber = ?', $courseNumber);
            if ($courseLetter) {
                $select->where('c.courseLetter = ?', $courseLetter);
            }
            $select->where('r.complete = "no"');
            */
            
            // First, check for requests based on a course with the given course code.
    
            $select = new Zend_Db_Select($db);
            $select->distinct();
            $select->from(array('c'  => 'creqCourseCodes'), array());
            $select->where('c.subject = ?', $subject);
            $select->where('c.courseNumber = ?', $courseNumber);
            $select->where('c.courseLetter = ?', $courseLetter);
            $select->join(array('x'  => 'creqCourseCrosslistings'), 'c.courseCodeId = x.courseCode', array());
            $select->join(array('g1' => 'creqCourseGenerations'), 'x.generation = g1.courseGenerationId', array());
            $select->where('g1.removed = ?', 'no');
            $select->join(array('p'  => 'creqCourses'), 'g1.courseGenerationId = p.currentGeneration', array());
            $select->join(array('g2' => 'creqCourseGenerations'), 'g1.course = g2.course', array());
            $select->join(array('r'  => 'creqRequests'), 'g2.request = r.requestId', array('requestId'));
            $select->where('r.complete = ?', 'no');
    
            $records = $select->query()->fetchAll();
            $requestIds = array();
            foreach ($records as $record) {
            	$requestIds[] = $record['requestId'];
            }
            
            // Second, check for New Course requests with the given course code.
            
            $select = new Zend_Db_Select($db);
            $select->distinct();
            $select->from(array('c'  => 'creqCourseCodes'), array());
            $select->where('c.subject = ?', $subject);
            $select->where('c.courseNumber = ?', $courseNumber);
            $select->where('c.courseLetter = ?', $courseLetter);
            $select->join(array('x'  => 'creqCourseCrosslistings'), 'c.courseCodeId = x.courseCode', array());
            $select->join(array('g1' => 'creqCourseGenerations'), 'x.generation = g1.courseGenerationId', array());
            $select->where('g1.type = ?', 'proposed');
            $select->join(array('r' => 'creqRequests'), 'g1.request = r.requestId', array('requestId'));
            $select->where('r.complete = ?', 'no');
            $select->join(array('t' => 'creqRequestTypes'), 'r.type = t.requestTypeId', array());
            $select->where('t.name LIKE ?', '%new%');
    
            $records = $select->query()->fetchAll();
            foreach ($records as $record) {
                $requestIds[] = $record['requestId'];
            }
            
            $requests = Requests_RequestModel::find($requestIds);
            return $requests;
    	}
    
    	static public function findAllActive()
    	{
            $db = Zend_Registry::get('db');
    
            $select = new Zend_Db_Select($db);
            $select->from(array('g' => 'creqCourseGenerations'), array('courseGenerationId'));
            $select->join(array('p' => 'creqCourses'), 'g.courseGenerationId = p.currentGeneration', array());
            $select->where('g.removed = "no"');
    
            $records = $select->query()->fetchAll();
            $generationIds = array();
            foreach ($records as $row) {
                $generationIds[] = $row['courseGenerationId'];
            }
            return self::find($generationIds);
    	}
    
    	static public function findWithCriteria(&$criteria = array(), $includeRemoved = false)
    	{
    		$validKeys = array('college', 'department', 'subject', 'courseNumber', 'courseLetter', 'title', 'campus', 'ace', 'aceOutcomes', 'essentialStudies', 'integratedStudies', 'activity');
    		$criteria = array_intersect_key($criteria, array_flip($validKeys));
    		$emptySearch = true;
    		foreach ($criteria as $value) {
    			if ($value) {
    				$emptySearch = false;
    			}
    		}
    		if ($emptySearch) {
    			return new Unl_Model_Collection(__CLASS__);
    		}
    
            $db = Zend_Registry::get('db');
    
            $select = new Zend_Db_Select($db);
            $select->from(array('l' => 'creqColleges'), array());
            $select->join(array('d' => 'creqDepartments'), 'l.collegeId = d.college', array());
            $select->join(array('s' => 'creqSubjects'), 'd.departmentId = s.department', array());
            $select->join(array('c' => 'creqCourseCodes'), 's.name = c.subject', array());
            $select->join(array('x' => 'creqCourseCrosslistings'), 'c.courseCodeId = x.courseCode', array());
            $select->join(array('g' => 'creqCourseGenerations'), 'x.generation = g.courseGenerationId', array());
            $select->join(array('p' => 'creqCourses'), 'g.course = p.courseId', array());
            $select->join(array('g2' => 'creqCourseGenerations'), 'p.currentGeneration = g2.courseGenerationId', array('courseGenerationId'));
            $select->join(array('e' => 'creqCourseDetails'), 'g.courseGenerationId = e.generation', array());
            if (!$includeRemoved) {
                $select->where('g.removed = "no"');
            }
            $select->where('g.type = "official"');
            if ($criteria['college']) {
                $select->where('l.collegeId = ?', $criteria['college']);
            }
            if ($criteria['department']) {
                $select->where('d.departmentId = ?', $criteria['department']);
            }
            if ($criteria['subject']) {
                $select->where('c.subject = ?', $criteria['subject']);
            }
            if ($criteria['courseNumber']) {
                $select->where('c.courseNumber LIKE ?', intval($criteria['courseNumber']) . '%');
            }
            if ($criteria['courseLetter']) {
                $select->where('c.courseLetter = ?', $criteria['courseLetter']);
            }
            if ($criteria['title']) {
                $select->where('e.title LIKE ?', '%' . $criteria['title'] . '%');
            }
            if ($criteria['campus']) {
                $select->where('e.campuses LIKE ?', '%' . $criteria['title'] . '%');
            }
            if (is_array($criteria['aceOutcomes'])) {
                $aceOutcomes = array('');
                $outcomeData = self::getAceOutcomeDataWithSloKey();
                foreach ($criteria['aceOutcomes'] as $slo) {
                    $aceOutcomes[] = $outcomeData['SLO' . $slo]['shortName'];
                }
            	$select->join(array('a' => 'creqCourseAceOutcomes'), 'g.courseGenerationId = a.generation', array());
            	$select->where('a.name IN (?)', $aceOutcomes);
            }
            if ($criteria['essentialStudies']) {
            	$select->join(array('es' => 'creqCourseEsDesignations'), 'c.courseCodeId = es.courseCode', array());
            }
            if ($criteria['integratedStudies']) {
            	$select->where('c.integratedStudies = ?', 'yes');
            }
            if (!$includeRemoved) {
                $select->where('g.courseGenerationId = g2.courseGenerationId');
            }
    
            $records = $select->query()->fetchAll();
            if (count($records) == 0) {
                return new Unl_Model_Collection(__CLASS__);;
            }
            $generationIds = array();
            foreach ($records as $record) {
            	$generationIds[] = $record['courseGenerationId'];
            }
            return self::find($generationIds);
    	}
    	
    	static public function findAllRequestsForCourse($courses, $completeApproveOnly = true)
    	{
    	    $multiple = true;
            if (!Unl_Util::isArray($courses)) {
                if (!($courses instanceof self)) {
                    throw new Exception('You must pass a ' . __CLASS__ . ' object or a collection of them.');
                }
                $collection = new Unl_Model_Collection(__CLASS__);
                $collection[] = $courses;
                $courses = $collection;
                $multiple = false;
            }
            
            if (count($courses) == 0) {
                return new Unl_Model_Collection(__CLASS__);
            }
            
            $db = Zend_Registry::get('db');
            $select = new Zend_Db_Select($db);
            
            $select->distinct();
            $select->from(array('g1' => 'creqCourseGenerations'), array('courseGenerationId'));
            $select->join(array('g2' => 'creqCourseGenerations'), 'g1.course = g2.course', array('request'));
            $select->join(array('r' => 'creqRequests'), 'g2.request = r.requestId', array());
            $select->where('g1.courseGenerationId IN (?)', $courses->getId());
            if ($completeApproveOnly) {
                $select->where('r.complete = ?', 'yes');
                $select->where('r.state = ?', 'Approve');
            }
            $records = $select->query()->fetchAll();
            
            $requestIds = array();
            foreach ($records as $row) {
                $requestIds[] = $row['request'];
            }
            
            $requests = Requests_RequestModel::find($requestIds);
    	
            $courseRequests = array();
            foreach ($courses as $course) {
                $courseRequests[$course->getId()] = new Unl_Model_Collection('Requests_RequestModel');
            }
            foreach ($records as $row) {
                $courseRequests[$row['courseGenerationId']][$row['request']] = $requests[$row['request']];
            }
            
            if (!$multiple) {
                return array_pop($courseRequests);
            } else {
                return $courseRequests;
            }
            
    	}
    
        static public function save($models)
        {
    
            if (!Unl_Util::isArray($models)) {
                $collection = new Unl_Model_Collection(__CLASS__);
                $collection[] = $models;
                $models = $collection;
            }
    
        	$db = Zend_Registry::get('db');
        	$db->beginTransaction();
    
        	$unsavedData = array();
        	foreach ($models as $id => $model) {
        	    $unsavedData[$id] = $model->_data;
        	}
    
        	try {
    
                $modelsToInsert = array();
                $modelsToUpdate = array();
                foreach ($models as $model) {
                	if ($model->getId()) {
                		$modelsToUpdate[] = $model;
                	} else {
                		$modelsToInsert[] = $model;
                	}
                }
                self::_insertBaseRows($modelsToInsert);
                self::_updateBaseRows($modelsToUpdate);
    
    
                $aceOutcomesToInsert = array();
                $aceOutcomesToUpdate = array();
                $aceOutcomesToDelete = array();
                foreach ($models as $model) {
                	if (!Unl_Util::isArray($model->_data['aceOutcomes'])) {
                		continue;
                	}
                    foreach ($model->_data['aceOutcomes'] as $id => &$aceOutcome) {
                        $aceOutcome['generation'] = $model->_data['courseGenerationId'];
    
                        $outcomeRef = array(
                            'model' => $model,
                            'id' => $id
                        );
    
                        if ($aceOutcome['courseAceOutcomeId']) {
                            $aceOutcomesToUpdate[] = $outcomeRef;
                        } else {
                            $aceOutcomesToInsert[] = $outcomeRef;
                        }
                    }
    
                    if (is_array($model->_cleanData['aceOutcomes'])) {
                        $aceOutcomesToDelete += array_diff_key($model->_cleanData['aceOutcomes'], $model->_data['aceOutcomes']);
                    }
                }
                self::_insertAceOutcomes($aceOutcomesToInsert);
                self::_updateAceOutcomes($aceOutcomesToUpdate);
                self::_deleteAceOutcomes($aceOutcomesToDelete);
    
                $aceReinforcementsToInsert = array();
                $aceReinforcementsToUpdate = array();
                $aceReinforcementsToDelete = array();
                foreach ($models as $model) {
                    if (!Unl_Util::isArray($model->_data['aceReinforcements'])) {
                        continue;
                    }
                    foreach ($model->_data['aceReinforcements'] as $id => &$aceReinforcement) {
                        $aceReinforcement['generation'] = $model->_data['courseGenerationId'];
    
                        $reinforcementRef = array(
                            'model'  => $model,
                            'id' => $id
                        );
    
                        if ($aceReinforcement['courseAceReinforcementId']) {
                            $aceReinforcementsToUpdate[] = $reinforcementRef;
                        } else {
                            $aceReinforcementsToInsert[] = $reinforcementRef;
                        }
                    }
    
                    if (is_array($model->_cleanData['aceReinforcements'])) {
                        $aceReinforcementsToDelete += array_diff_key($model->_cleanData['aceReinforcements'], $model->_data['aceReinforcements']);
                    }
                }
                self::_insertAceReinforcements($aceReinforcementsToInsert);
                self::_updateAceReinforcements($aceReinforcementsToUpdate);
                self::_deleteAceReinforcements($aceReinforcementsToDelete);
    
                $activitiesToInsert = array();
                $activitiesToUpdate = array();
                $activitiesToDelete = array();
                foreach ($models as $model) {
                    foreach ($model->_data['activities'] as $id => &$activity) {
                        $activity['generation'] = $model->_data['courseGenerationId'];
    
                        $activityRef = array(
                            'model'  => $model,
                            'id' => $id
                        );
    
                        if ($activity['courseActivityId']) {
                            $activitiesToUpdate[] = $activityRef;
                        } else {
                            $activitiesToInsert[] = $activityRef;
                        }
                    }
    
                    if (is_array($model->_cleanData['activities'])) {
                        $keysToDelete = array_diff_key($model->_cleanData['activities'], $model->_data['activities']);
                        foreach ($keysToDelete as $keyToDelete) {
                            $activitiesToDelete[] = $model->_cleanData['activities'][$keyToDelete]['courseActivityId'];
                        }
                    }
                }
                self::_insertActivities($activitiesToInsert);
                self::_updateActivities($activitiesToUpdate);
                self::_deleteActivities($activitiesToDelete);
    
                $creditsToInsert = array();
                $creditsToUpdate = array();
                $creditsToDelete = array();
                foreach ($models as $model) {
                    foreach ($model->_data['credits'] as $id => &$credit) {
                        $credit['generation'] = $model->_data['courseGenerationId'];
    
                        $creditRef = array(
                            'model'  => $model,
                            'id' => $id
                        );
    
                        if ($credit['courseCreditId']) {
                            $creditsToUpdate[] = $creditRef;
                        } else {
                            $creditsToInsert[] = $creditRef;
                        }
                    }
    
                    if (is_array($model->_cleanData['credits'])) {
                        $keysToDelete = array_diff_key($model->_cleanData['credits'], $model->_data['credits']);
                        foreach ($keysToDelete as $keyToDelete) {
                            $activitiesToDelete[] = $model->_cleanData['credits'][$keyToDelete]['courseCreditId'];
                        }
                    }
                }
                self::_insertCredits($creditsToInsert);
                self::_updateCredits($creditsToUpdate);
                self::_deleteCredits($creditsToDelete);
    
                $courseCodesToInsert = array();
                foreach ($models as $model) {
                    foreach ($model->_data['crosslistings'] as $id => &$crosslisting) {
                        $crosslisting['generation'] = $model->_data['courseGenerationId'];
    
                        $courseCodesToInsert[] = array(
                            'subject'      => $crosslisting['subject'],
                            'courseNumber' => $crosslisting['courseNumber'],
                            'courseLetter' => $crosslisting['courseLetter']
                        );
                    }
                }
                $courseCodeMap = self::_getCourseCodeMap($courseCodesToInsert);
    
                $crosslistingsToInsert = array();
                $crosslistingsToUpdate = array();
                $crosslistingsToDelete = array();
                foreach ($models as $model) {
                    foreach ($model->_data['crosslistings'] as $id => &$crosslisting) {
                        $crosslisting['generation'] = $model->_data['courseGenerationId'];
                        $key = $crosslisting['subject'] . $crosslisting['courseNumber'] . $crosslisting['courseLetter'];
                        $crosslisting['courseCode'] = $courseCodeMap[$key]['courseCodeId'];
    
                        $crosslistingRef = array(
                            'model'  => $model,
                            'id' => $id
                        );
    
                        if ($crosslisting['courseCrosslistingId']) {
                            $crosslistingsToUpdate[] = $crosslistingRef;
                        } else {
                            $crosslistingsToInsert[] = $crosslistingRef;
                        }
                    }
    
                    if (is_array($model->_cleanData['crosslistings'])) {
                        $keysToDelete = array_diff_key($model->_cleanData['crosslistings'], $model->_data['crosslistings']);
                        foreach ($keysToDelete as $keyToDelete) {
                            $activitiesToDelete[] = $model->_cleanData['crosslistings'][$keyToDelete]['courseCrosslistingId'];
                        }
                    }
                }
                self::_insertCrosslistings($crosslistingsToInsert);
                self::_updateCrosslistings($crosslistingsToUpdate);
                self::_deleteCrosslistings($crosslistingsToDelete);
    
                $gradTieInsToInsert = array();
                $gradTieInsToUpdate = array();
                $gradTieInsToDelete = array();
                foreach ($models as $model) {
                    if (is_array($model->_data['gradTieIn'])) {
                        $model->_data['gradTieIn']['generation'] = $model->_data['courseGenerationId'];
                        if ($model->_data['gradTieIn']['courseGradTieInId']) {
                            $gradTieInsToUpdate[] = $model;
                        } else {
                            $gradTieInsToInsert[] = $model;
                        }
                    }
    
                    if (is_array($model->_cleanData['gradTieIn']) && !is_array($model->_data['gradTieIn'])) {
                        $gradTieInsToDelete[] = $model->_cleanData['gradTieIn']['courseGradTieInId'];
                    }
                }
                self::_insertGradTieIns($gradTieInsToInsert);
                self::_updateGradTieIns($gradTieInsToUpdate);
                self::_deleteGradTieIns($gradTieInsToDelete);
    
                $db->commit();
        	} catch (Exception $e) {
        	    $db->rollback();
            	foreach ($models as $id => $model) {
            	    $model->_data = $unsavedData[$id];
            	}
        	    throw $e;
        	}
        }
    
        static public function _insertBaseRows($models)
        {
            if (count($models) == 0) {
                return;
            }
    
            $db = Zend_Registry::get('db');
    
            $sql = 'INSERT INTO creqAssets (creationTime, modifiedTime) VALUES ';
            $sqlParts = array();
            foreach ($models as $model) {
                $sqlParts[] = $db->quoteInto('(?, ', time())
                            . $db->quoteInto('?)'  , time());
            }
            $sql .= implode(', ', $sqlParts);
            $db->query($sql);
    
            $lastId = $db->lastInsertId();
            foreach ($models as $model) {
                $model->_data['assetId'] = $lastId;
                $lastId++;
            }
    
            $sql = 'INSERT INTO creqCourses (currentGeneration) VALUES ';
            $sqlParts = array();
            foreach ($models as $model) {
            	if ($model->_data['course']) {
            		continue;
            	}
                $sqlParts[] = '(NULL)';
            }
            if (count($sqlParts) > 0) {
                $sql .= implode(', ', $sqlParts);
                $db->query($sql);
    
    	        $lastId = $db->lastInsertId();
    	        foreach ($models as $model) {
    	        	if ($model->_data['course']) {
    	        		continue;
    	        	}
                    $model->_data['course'] = $lastId;
                    $model->_data['courseId'] = $lastId;
    	            $lastId++;
    	        }
            }
    
    
            $sql = 'INSERT INTO creqCourseGenerations (assetId, parent, course, request, type, removed) VALUES ';
            $sqlParts = array();
            foreach ($models as $model) {
                $sqlParts[] = $db->quoteInto('(?, ', $model->_data['assetId'])
                            . $db->quoteInto('?, ' , $model->_data['parent'])
                            . $db->quoteInto('?, ' , $model->_data['course'])
                            . $db->quoteInto('?, ' , $model->_data['request'])
                            . $db->quoteInto('?, ' , $model->_data['type'])
                            . $db->quoteInto('?)'  , $model->_data['removed']);
            }
            $sql .= implode(', ', $sqlParts);
            $db->query($sql);
    
            $lastId = $db->lastInsertId();
            foreach ($models as $model) {
                $model->_data['courseGenerationId'] = $lastId;
                $model->_data['generation'] = $lastId;
                $lastId++;
            }
    
    
            $sql = 'INSERT INTO creqCourseDetails (generation, title, gradingType, dfRemoval, campuses, deliveryMethods, termsOffered, effectiveSemester, finalSemester, prerequisite, notes, description) VALUES ';
            $sqlParts = array();
            foreach ($models as $model) {
                $sqlParts[] = $db->quoteInto('(?, ', $model->_data['courseGenerationId'])
                            . $db->quoteInto('?, ' , $model->_data['title'])
                            . $db->quoteInto('?, ' , $model->_data['gradingType'])
                            . $db->quoteInto('?, ' , $model->_data['dfRemoval'])
                            . $db->quoteInto('?, ' , implode(',', $model->_data['campuses']))
                            . $db->quoteInto('?, ' , implode(',', $model->_data['deliveryMethods']))
                            . $db->quoteInto('?, ' , implode(',', $model->_data['termsOffered']))
                            . $db->quoteInto('?, ' , $model->_data['effectiveSemester'])
                            . $db->quoteInto('?, ' , $model->_data['finalSemester'])
                            . $db->quoteInto('?, ' , $model->_data['prerequisite'])
                            . $db->quoteInto('?, ' , $model->_data['notes'])
                            . $db->quoteInto('?)'  , $model->_data['description']);
            }
            $sql .= implode(', ', $sqlParts);
            $db->query($sql);
    
            $lastId = $db->lastInsertId();
            foreach ($models as $model) {
                $model->_data['courseDetailId'] = $lastId;
                $lastId++;
            }
    
        }
    
        static public function _updateBaseRows($models)
        {
            if (count($models) == 0) {
                return;
            }
    
            $db = Zend_Registry::get('db');
    
    
            // Update the assets table
            $sql = 'CREATE TEMPORARY TABLE creqAssetsUpdate '
                 . 'SELECT * FROM creqAssets LIMIT 0';
            $db->query($sql);
    
            $sql = 'INSERT INTO creqAssetsUpdate VALUES ';
            $sqlParts = array();
            foreach ($models as $model) {
                $sqlParts[] = $db->quoteInto('(?, ', $model->_data['assetId'])
                            . $db->quoteInto('?, ' , time())
                            . $db->quoteInto('?)'  , time());
            }
            $sql .= implode(', ', $sqlParts);
            $db->query($sql);
    
            $sql = 'UPDATE creqAssets AS a, '
                 . '       creqAssetsUpdate AS b '
                 . 'SET a.modifiedTime = b.modifiedTime '
                 . 'WHERE a.assetId = b.assetId ';
            $db->query($sql);
            $db->query('DROP TABLE creqAssetsUpdate');
    
    
            // Update the courses table
            $sql = 'CREATE TEMPORARY TABLE creqCoursesUpdate '
                 . 'SELECT * FROM creqCourses LIMIT 0';
            $db->query($sql);
    
            $sql = 'INSERT INTO creqCoursesUpdate VALUES ';
            $sqlParts = array();
            foreach ($models as $model) {
                $sqlParts[] = $db->quoteInto('(?, ', $model->_data['course'])
                            . $db->quoteInto('?)'  , $model->_data['currentGeneration']);
            }
            $sql .= implode(', ', $sqlParts);
            $db->query($sql);
    
            $sql = 'UPDATE creqCourses AS a, '
                 . '       creqCoursesUpdate AS b '
                 . 'SET a.currentGeneration = b.currentGeneration '
                 . 'WHERE a.courseId = b.courseId ';
            $db->query($sql);
            $db->query('DROP TABLE creqCoursesUpdate');
    
    
            // Update the courseGenerations table
            $sql = 'CREATE TEMPORARY TABLE creqCourseGenerationsUpdate '
                 . 'SELECT * FROM creqCourseGenerations LIMIT 0';
            $db->query($sql);
    
            $sql = 'INSERT INTO creqCourseGenerationsUpdate VALUES ';
            $sqlParts = array();
            foreach ($models as $model) {
                $sqlParts[] = $db->quoteInto('(?, ', $model->_data['courseGenerationId'])
                            . $db->quoteInto('?, ' , $model->_data['assetId'])
                            . $db->quoteInto('?, ' , $model->_data['parent'])
                            . $db->quoteInto('?, ' , $model->_data['course'])
                            . $db->quoteInto('?, ' , $model->_data['request'])
                            . $db->quoteInto('?, ' , $model->_data['type'])
                            . $db->quoteInto('?)'  , $model->_data['removed']);
            }
            $sql .= implode(', ', $sqlParts);
            $db->query($sql);
    
            $sql = 'UPDATE creqCourseGenerations AS a, '
                 . '       creqCourseGenerationsUpdate AS b '
                 . 'SET a.assetId = b.assetId, '
                 . '    a.parent  = b.parent, '
                 . '    a.course  = b.course, '
                 . '    a.request = b.request, '
                 . '    a.type    = b.type, '
                 . '    a.removed = b.removed '
                 . 'WHERE a.courseGenerationId = b.courseGenerationId ';
            $db->query($sql);
            $db->query('DROP TABLE creqCourseGenerationsUpdate');
    
    
            // Update the courseDetails table
            $sql = 'CREATE TEMPORARY TABLE creqCourseDetailsUpdate '
                 . 'SELECT * FROM creqCourseDetails LIMIT 0';
            $db->query($sql);
    
            $sql = 'INSERT INTO creqCourseDetailsUpdate VALUES ';
            $sqlParts = array();
            foreach ($models as $model) {
                $sqlParts[] = $db->quoteInto('(?, ', $model->_data['courseDetailId'])
                            . $db->quoteInto('?, ' , $model->_data['generation'])
                            . $db->quoteInto('?, ' , $model->_data['title'])
                            . $db->quoteInto('?, ' , $model->_data['gradingType'])
                            . $db->quoteInto('?, ' , $model->_data['dfRemoval'])
                            . $db->quoteInto('?, ' , implode(',', $model->_data['campuses']))
                            . $db->quoteInto('?, ' , implode(',', $model->_data['deliveryMethods']))
                            . $db->quoteInto('?, ' , implode(',', $model->_data['termsOffered']))
                            . $db->quoteInto('?, ' , $model->_data['effectiveSemester'])
                            . $db->quoteInto('?, ' , $model->_data['finalSemester'])
                            . $db->quoteInto('?, ' , $model->_data['prerequisite'])
                            . $db->quoteInto('?, ' , $model->_data['notes'])
                            . $db->quoteInto('?)'  , $model->_data['description']);
            }
            $sql .= implode(', ', $sqlParts);
            $db->query($sql);
    
            $sql = 'UPDATE creqCourseDetails AS a, '
                 . '       creqCourseDetailsUpdate AS b '
                 . 'SET a.generation        = b.generation, '
                 . '    a.title             = b.title, '
                 . '    a.gradingType       = b.gradingType, '
                 . '    a.dfRemoval         = b.dfRemoval, '
                 . '    a.campuses          = b.campuses, '
                 . '    a.deliveryMethods   = b.deliveryMethods, '
                 . '    a.termsOffered      = b.termsOffered, '
                 . '    a.effectiveSemester = b.effectiveSemester, '
                 . '    a.finalSemester     = b.finalSemester, '
                 . '    a.prerequisite      = b.prerequisite, '
                 . '    a.notes             = b.notes, '
                 . '    a.description       = b.description '
                 . 'WHERE a.courseDetailId = b.courseDetailId ';
            $db->query($sql);
            $db->query('DROP TABLE creqCourseDetailsUpdate');
        }
    
        static public function _insertAceOutcomes($models)
        {
            if (count($models) == 0) {
                return;
            }
    
            $db = Zend_Registry::get('db');
    
            $sql = 'INSERT INTO creqCourseAceOutcomes (generation, name, justification, studentWork, assesmentPlan) VALUES ';
            $sqlParts = array();
            foreach ($models as $model) {
                $outcome = $model['model']->_data['aceOutcomes'][$model['id']];
                $sqlParts[] = $db->quoteInto('(?, ', $outcome['generation'])
                            . $db->quoteInto('?, ' , $outcome['name'])
                            . $db->quoteInto('?, ' , $outcome['justification'])
                            . $db->quoteInto('?, ' , $outcome['studentWork'])
                            . $db->quoteInto('?)'  , $outcome['assesmentPlan']);
            }
            $sql .= implode(', ', $sqlParts);
    
            $db->query($sql);
    
            $lastId = $db->lastInsertId();
            foreach ($models as $model) {
                $model['model']->_data['aceOutcomes'][$model['id']]['courseAceOutcomeId'] = $lastId;
                $lastId++;
            }
        }
    
        static public function _updateAceOutcomes($models)
        {
            if (count($models) == 0) {
                return;
            }
    
            $db = Zend_Registry::get('db');
    
            $sql = 'CREATE TEMPORARY TABLE creqCourseAceOutcomesUpdate '
                 . 'SELECT * FROM creqCourseAceOutcomes LIMIT 0';
            $db->query($sql);
    
            $sql = 'INSERT INTO creqCourseAceOutcomesUpdate VALUES ';
            $sqlParts = array();
            foreach ($models as $model) {
                $outcome = $model['model']->_data['aceOutcomes'][$model['id']];
                $sqlParts[] = $db->quoteInto('(?, ', $outcome['courseAceOutcomeId'])
                            . $db->quoteInto('?, ' , $outcome['generation'])
                            . $db->quoteInto('?, ' , $outcome['name'])
                            . $db->quoteInto('?, ' , $outcome['justification'])
                            . $db->quoteInto('?, ' , $outcome['studentWork'])
                            . $db->quoteInto('?)'  , $outcome['assesmentPlan']);
            }
            $sql .= implode(', ', $sqlParts);
            $db->query($sql);
    
            $sql = 'UPDATE creqCourseAceOutcomes AS a, '
                 . '       creqCourseAceOutcomesUpdate AS b '
                 . 'SET a.generation    = b.generation, '
                 . '    a.name          = b.name, '
                 . '    a.justification = b.justification, '
                 . '    a.studentWork   = b.studentWork, '
                 . '    a.assesmentPlan = b.assesmentPlan '
                 . 'WHERE a.courseAceOutcomeId = b.courseAceOutcomeId ';
    
            $db->query($sql);
            $db->query('DROP TABLE creqCourseAceOutcomesUpdate');
        }
    
        static public function _deleteAceOutcomes($models)
        {
            if (count($models) == 0) {
                return;
            }
    
            $db = Zend_Registry::get('db');
    
            $sql = $db->quoteInto('DELETE FROM creqCourseAceOutcomes WHERE courseAceOutcomeId IN (?)', array_keys($models));
            $db->query($sql);
        }
    
        static public function _insertAceReinforcements($models)
        {
            if (count($models) == 0) {
                return;
            }
    
            $db = Zend_Registry::get('db');
    
            $sql = 'INSERT INTO creqCourseAceReinforcements (generation, name, description) VALUES ';
            $sqlParts = array();
            foreach ($models as $model) {
                $reinforcement = $model['model']->_data['aceReinforcements'][$model['id']];
                $sqlParts[] = $db->quoteInto('(?, ', $reinforcement['generation'])
                            . $db->quoteInto('?, ' , $reinforcement['name'])
                            . $db->quoteInto('?)'  , $reinforcement['description']);
            }
            $sql .= implode(', ', $sqlParts);
    
            $db->query($sql);
    
            $lastId = $db->lastInsertId();
            foreach ($models as $model) {
                $model['model']->_data['aceReinforcements'][$model['id']]['courseAceReinforcementId'] = $lastId;
                $lastId++;
            }
        }
    
        static public function _updateAceReinforcements($models)
        {
            if (count($models) == 0) {
                return;
            }
    
            $db = Zend_Registry::get('db');
    
            $sql = 'CREATE TEMPORARY TABLE creqCourseAceReinforcementsUpdate '
                 . 'SELECT * FROM creqCourseAceReinforcements LIMIT 0';
            $db->query($sql);
    
            $sql = 'INSERT INTO creqCourseAceReinforcementsUpdate VALUES ';
            $sqlParts = array();
            foreach ($models as $model) {
                $reinforcement = $model['model']->_data['aceReinforcements'][$model['id']];
                $sqlParts[] = $db->quoteInto('(?, ', $reinforcement['courseAceReinforcementId'])
                            . $db->quoteInto('?, ' , $reinforcement['generation'])
                            . $db->quoteInto('?, ' , $reinforcement['name'])
                            . $db->quoteInto('?)'  , $reinforcement['description']);
            }
            $sql .= implode(', ', $sqlParts);
            $db->query($sql);
    
            $sql = 'UPDATE creqCourseAceReinforcements AS a, '
                 . '       creqCourseAceReinforcementsUpdate AS b '
                 . 'SET a.generation    = b.generation, '
                 . '    a.name          = b.name, '
                 . '    a.description   = b.description '
                 . 'WHERE a.courseAceReinforcementId = b.courseAceReinforcementId ';
    
            $db->query($sql);
            $db->query('DROP TABLE creqCourseAceReinforcementsUpdate');
        }
    
        static public function _deleteAceReinforcements($models)
        {
            if (count($models) == 0) {
                return;
            }
    
            $db = Zend_Registry::get('db');
    
            $sql = $db->quoteInto('DELETE FROM creqCourseAceReinforcements WHERE courseAceReinforcementId IN (?)', array_keys($models));
            $db->query($sql);
        }
    
        static public function _insertActivities($models)
        {
            if (count($models) == 0) {
                return;
            }
    
            $db = Zend_Registry::get('db');
    
            $sql = 'INSERT INTO creqCourseActivities (generation, type, hours) VALUES ';
            $sqlParts = array();
            foreach ($models as $model) {
                $activty = $model['model']->_data['activities'][$model['id']];
                $sqlParts[] = $db->quoteInto('(?, ', $activty['generation'])
                            . $db->quoteInto('?, ' , $activty['type'])
                            . $db->quoteInto('?)'  , $activty['hours']);
            }
            $sql .= implode(', ', $sqlParts);
            $db->query($sql);
    
            $lastId = $db->lastInsertId();
            foreach ($models as $model) {
                $model['model']->_data['activities'][$model['id']]['courseActivityId'] = $lastId;
                $lastId++;
            }
        }
    
        static public function _updateActivities($models)
        {
            if (count($models) == 0) {
                return;
            }
    
            $db = Zend_Registry::get('db');
    
            $sql = 'CREATE TEMPORARY TABLE creqCourseActivitiesUpdate '
                 . 'SELECT * FROM creqCourseActivities LIMIT 0';
            $db->query($sql);
    
            $sql = 'INSERT INTO creqCourseActivitiesUpdate VALUES ';
            $sqlParts = array();
            foreach ($models as $model) {
                $activity = $model['model']->_data['activities'][$model['id']];
                $sqlParts[] = $db->quoteInto('(?, ', $activity['courseActivityId'])
                            . $db->quoteInto('?, ' , $activity['generation'])
                            . $db->quoteInto('?, ' , $activity['type'])
                            . $db->quoteInto('?)'  , $activity['hours']);
            }
            $sql .= implode(', ', $sqlParts);
            $db->query($sql);
    
            $sql = 'UPDATE creqCourseActivities AS a, '
                 . '       creqCourseActivitiesUpdate AS b '
                 . 'SET a.generation    = b.generation, '
                 . '    a.type          = b.type, '
                 . '    a.hours         = b.hours '
                 . 'WHERE a.courseActivityId = b.courseActivityId ';
    
            $db->query($sql);
            $db->query('DROP TABLE creqCourseActivitiesUpdate');
        }
    
        static public function _deleteActivities($models)
        {
            if (count($models) == 0) {
                return;
            }
    
            $db = Zend_Registry::get('db');
    
            $sql = $db->quoteInto('DELETE FROM creqCourseActivities WHERE courseActivityId IN (?)', $models);
            $db->query($sql);
        }
    
        static public function _insertCredits($models)
        {
            if (count($models) == 0) {
                return;
            }
    
            $db = Zend_Registry::get('db');
    
            $sql = 'INSERT INTO creqCourseCredits (generation, type, hours) VALUES ';
            $sqlParts = array();
            foreach ($models as $model) {
                $credit = $model['model']->_data['credits'][$model['id']];
                $sqlParts[] = $db->quoteInto('(?, ', $credit['generation'])
                            . $db->quoteInto('?, ' , $credit['type'])
                            . $db->quoteInto('?)'  , $credit['hours']);
            }
            $sql .= implode(', ', $sqlParts);
            $db->query($sql);
    
            $lastId = $db->lastInsertId();
            foreach ($models as $model) {
                $model['model']->_data['credits'][$model['id']]['courseCreditId'] = $lastId;
                $lastId++;
            }
        }
    
        static public function _updateCredits($models)
        {
            if (count($models) == 0) {
                return;
            }
    
            $db = Zend_Registry::get('db');
    
            $sql = 'CREATE TEMPORARY TABLE creqCourseCreditsUpdate '
                 . 'SELECT * FROM creqCourseCredits LIMIT 0';
            $db->query($sql);
    
            $sql = 'INSERT INTO creqCourseCreditsUpdate VALUES ';
            $sqlParts = array();
            foreach ($models as $model) {
                $credit = $model['model']->_data['credits'][$model['id']];
                $sqlParts[] = $db->quoteInto('(?, ', $credit['courseCreditId'])
                            . $db->quoteInto('?, ' , $credit['generation'])
                            . $db->quoteInto('?, ' , $credit['type'])
                            . $db->quoteInto('?)'  , $credit['hours']);
            }
            $sql .= implode(', ', $sqlParts);
            $db->query($sql);
    
            $sql = 'UPDATE creqCourseCredits AS a, '
                 . '       creqCourseCreditsUpdate AS b '
                 . 'SET a.generation    = b.generation, '
                 . '    a.type          = b.type, '
                 . '    a.hours         = b.hours '
                 . 'WHERE a.courseCreditId = b.courseCreditId ';
    
            $db->query($sql);
            $db->query('DROP TABLE creqCourseCreditsUpdate');
        }
    
        static public function _deleteCredits($models)
        {
            if (count($models) == 0) {
                return;
            }
    
            $db = Zend_Registry::get('db');
    
            $sql = $db->quoteInto('DELETE FROM creqCourseCredits WHERE creqCourseCreditId IN (?)', $models);
            $db->query($sql);
        }
    
        static public function _getCourseCodeMap($courseCodes)
        {
            if (count($courseCodes) == 0) {
                return array();
            }
    
            $db = Zend_Registry::get('db');
    
            $select = new Zend_Db_Select($db);
            $select->from('creqCourseCodes');
            foreach ($courseCodes as $courseCode) {
                $where = $db->quoteInto('subject = ? ', $courseCode['subject'])
                       . $db->quoteInto('AND courseNumber = ? ', $courseCode['courseNumber'])
                       . $db->quoteInto('AND courseLetter = ? ', $courseCode['courseLetter']);
                $select->orWhere($where);
            }
            $data = $select->query()->fetchAll();
            $existingCourseCodes = array();
            foreach ($data as $row) {
                $key = $row['subject'] . $row['courseNumber'] . $row['courseLetter'];
                $existingCourseCodes[$key] = $row;
            }
    
            $missingCourseCodes = array();
            foreach ($courseCodes as $courseCode) {
                $key = $courseCode['subject'] . $courseCode['courseNumber'] . $courseCode['courseLetter'];
                if (!array_key_exists($key, $existingCourseCodes)) {
                    $missingCourseCodes[] = $courseCode;
                }
            }
    
            if (count($missingCourseCodes) == 0) {
                return $existingCourseCodes;
            }
    
            $sql = 'INSERT INTO creqCourseCodes (subject, courseNumber, courseLetter) VALUES ';
            $sqlParts = array();
            foreach ($missingCourseCodes as $courseCode) {
                $sqlParts[] = $db->quoteInto('(?, ', $courseCode['subject'])
                            . $db->quoteInto('?, ',  $courseCode['courseNumber'])
                            . $db->quoteInto('?)',   $courseCode['courseLetter']);
            }
            $sql .= implode(', ', $sqlParts);
            $db->query($sql);
    
            $lastId = $db->lastInsertId();
            foreach ($missingCourseCodes as $courseCode) {
                $key = $courseCode['subject'] . $courseCode['courseNumber'] . $courseCode['courseLetter'];
                $courseCode['courseCodeId'] = $lastId;
                $lastId++;
                $existingCourseCodes[$key] = $courseCode;
            }
    
            return $existingCourseCodes;
        }
    
        static public function _insertCrosslistings($models)
        {
            if (count($models) == 0) {
                return;
            }
    
            $db = Zend_Registry::get('db');
    
            $sql = 'INSERT INTO creqCourseCrosslistings (generation, type, courseCode) VALUES ';
            $sqlParts = array();
            foreach ($models as $model) {
                $crosslisting = $model['model']->_data['crosslistings'][$model['id']];
                $sqlParts[] = $db->quoteInto('(?, ', $crosslisting['generation'])
                            . $db->quoteInto('?, ' , $crosslisting['type'])
                            . $db->quoteInto('?)'  , $crosslisting['courseCode']);
            }
            $sql .= implode(', ', $sqlParts);
            $db->query($sql);
    
            $lastId = $db->lastInsertId();
            foreach ($models as $model) {
                $model['model']->_data['crosslistings'][$model['id']]['courseCrosslistingId'] = $lastId;
                $lastId++;
            }
        }
    
        static public function _updateCrosslistings($models)
        {
            if (count($models) == 0) {
                return;
            }
    
            $db = Zend_Registry::get('db');
    
            $sql = 'CREATE TEMPORARY TABLE creqCourseCrosslistingsUpdate '
                 . 'SELECT * FROM creqCourseCrosslistings LIMIT 0';
            $db->query($sql);
    
            $sql = 'INSERT INTO creqCourseCrosslistingsUpdate VALUES ';
            $sqlParts = array();
            foreach ($models as $model) {
                $crosslisting = $model['model']->_data['crosslistings'][$model['id']];
                $sqlParts[] = $db->quoteInto('(?, ', $crosslisting['courseCrosslistingId'])
                            . $db->quoteInto('?, ' , $crosslisting['generation'])
                            . $db->quoteInto('?, ' , $crosslisting['type'])
                            . $db->quoteInto('?)'  , $crosslisting['courseCode']);
            }
            $sql .= implode(', ', $sqlParts);
            $db->query($sql);
    
            $sql = 'UPDATE creqCourseCrosslistings AS a, '
                 . '       creqCourseCrosslistingsUpdate AS b '
                 . 'SET a.generation = b.generation, '
                 . '    a.type       = b.type, '
                 . '    a.courseCode = b.courseCode '
                 . 'WHERE a.courseCrosslistingId = b.courseCrosslistingId ';
    
            $db->query($sql);
            $db->query('DROP TABLE creqCourseCrosslistingsUpdate');
        }
    
        static public function _deleteCrosslistings($models)
        {
            if (count($models) == 0) {
                return;
            }
    
            $db = Zend_Registry::get('db');
    
            $sql = $db->quoteInto('DELETE FROM creqCourseCrosslistings WHERE creqCourseCrosslistingId IN (?)', $models);
            $db->query($sql);
        }
    
        static public function _insertGradTieIns($models)
        {
            if (count($models) == 0) {
                return;
            }
    
            $db = Zend_Registry::get('db');
    
            $sql = 'INSERT INTO creqCourseGradTieIns (generation, credits, notes, prerequisites) VALUES ';
            $sqlParts = array();
            foreach ($models as $model) {
                $gradTieIn = $model->_data['gradTieIn'];
                $sqlParts[] = $db->quoteInto('(?, ', $gradTieIn['generation'])
                            . $db->quoteInto('?, ' , $gradTieIn['credits'])
                            . $db->quoteInto('?, ' , $gradTieIn['notes'])
                            . $db->quoteInto('?)'  , $gradTieIn['prerequisites']);
            }
            $sql .= implode(', ', $sqlParts);
            $db->query($sql);
    
            $lastId = $db->lastInsertId();
            foreach ($models as $model) {
                $model->_data['gradTieIn']['courseGradTieInId'] = $lastId;
                $lastId++;
            }
        }
    
        static public function _updateGradTieIns($models)
        {
            if (count($models) == 0) {
                return;
            }
    
            $db = Zend_Registry::get('db');
    
            $sql = 'CREATE TEMPORARY TABLE creqCourseGradTieInsUpdate '
                 . 'SELECT * FROM creqCourseGradTieIns LIMIT 0';
            $db->query($sql);
    
            $sql = 'INSERT INTO creqCourseGradTieInsUpdate VALUES ';
            $sqlParts = array();
            foreach ($models as $model) {
                $gradTieIn = $model->_data['gradTieIn'];
                $sqlParts[] = $db->quoteInto('(?, ', $gradTieIn['courseGradTieInId'])
                            . $db->quoteInto('?, ' , $gradTieIn['generation'])
                            . $db->quoteInto('?, ' , $gradTieIn['credits'])
                            . $db->quoteInto('?, ' , $gradTieIn['notes'])
                            . $db->quoteInto('?)'  , $gradTieIn['prerequisites']);
            }
            $sql .= implode(', ', $sqlParts);
            $db->query($sql);
    
            $sql = 'UPDATE creqCourseGradTieIns AS a, '
                 . '       creqCourseGradTieInsUpdate AS b '
                 . 'SET a.generation    = b.generation, '
                 . '    a.credits       = b.credits, '
                 . '    a.notes         = b.notes, '
                 . '    a.prerequisites = b.prerequisites '
                 . 'WHERE a.courseGradTieInId = b.courseGradTieInId ';
    
            $db->query($sql);
            $db->query('DROP TABLE creqCourseGradTieInsUpdate');
        }
    
        static public function _deleteGradTieIns($models)
        {
            if (count($models) == 0) {
                return;
            }
    
            $db = Zend_Registry::get('db');
    
            $sql = $db->quoteInto('DELETE FROM creqCourseGradTieIns WHERE courseGradTieInId IN (?)', $models);
            $db->query($sql);
        }
    
    	public function __clone()
    	{
    		$this->_data['parent'] = $this->getId();
    		$this->_data['type'] = 'proposed';
    
            unset($this->_data['assetId']);
            unset($this->_data['courseGenerationId']);
            unset($this->_data['courseDetailId']);
    
    		foreach ($this->_data['aceOutcomes'] as &$aceOutcome) {
                unset ($aceOutcome['courseAceOutcomeId']);
                unset ($aceOutcome['generation']);
    		}
            foreach ($this->_data['aceReinforcements'] as &$aceReinforcement) {
                unset ($aceReinforcement['courseAceReinforcementId']);
                unset ($aceReinforcement['generation']);
            }
            foreach ($this->_data['activities'] as &$activity) {
                unset ($activity['courseActivityId']);
                unset ($activity['generation']);
            }
            foreach ($this->_data['credits'] as &$credit) {
                unset ($credit['courseCreditId']);
                unset ($credit['generation']);
            }
            foreach ($this->_data['crosslistings'] as &$crosslisting) {
                unset ($crosslisting['courseCrosslistingId']);
                unset ($crosslisting['generation']);
            }
    	}
    
    	public function getId()
    	{
    		return $this->_data['courseGenerationId'];
    	}
    
        public function getSubject()
        {
            $homeSubject = '';
            foreach ($this->_data['crosslistings'] as $crosslisting) {
                if ($crosslisting['type'] != 'home listing') {
                    continue;
                }
                $homeSubject = $crosslisting['subject'];
            }
            return $homeSubject;
        }
    
        static public function getSubjects()
        {
            self::_loadSubjectList();
            return self::$_subjectList;
        }
    
        static public function getSubjectNames()
        {
            self::_loadSubjectList();
            return self::$_subjectNames;
        }
    
        static public function getSubjectsFull()
        {
            self::_loadSubjectList();
            $subjects = array();
            foreach (self::$_subjectList as $id => $code) {
            	$subjects[$code] = $code . ' - ' . self::$_subjectNames[$id];
            }
            return $subjects;
        }
    
        static public function getSubjectDepartmentCollegeHierarchy()
        {
            if (count(self::$_hierarchy) == 0) {
                $db = Zend_Registry::get('db');
                $select = new Zend_Db_Select($db);
                $select->from(array('c' => 'creqColleges'), array('collegeId', 'college' => 'description'));
                $select->join(array('d' => 'creqDepartments'), 'c.collegeId = d.college', array('departmentId', 'department' => 'name'));
                $select->join(array('s' => 'creqSubjects'), 'd.departmentId = s.department', array('code' => 'name', 'subject' => 'description'));
                $select->order(array('college', 'department', 'subject'));
                $records = $select->query()->fetchAll();
                $hierarchy = array();
                foreach ($records as $record) {
                    $hierarchy[$record['collegeId']]['name'] = $record['college'];
                    $hierarchy[$record['collegeId']]['departments'][$record['departmentId']]['name'] = $record['department'];
                    $hierarchy[$record['collegeId']]['departments'][$record['departmentId']]['subjects'][$record['code']] = $record['subject'];
                }
                self::$_hierarchy = $hierarchy;
            }
            return self::$_hierarchy;
        }
    
    
        public function getCourseNumber()
        {
            $homeNumber = '';
            foreach ($this->_data['crosslistings'] as $crosslisting) {
                if ($crosslisting['type'] != 'home listing') {
                    continue;
                }
                $homeNumber = $crosslisting['courseNumber'];
            }
            return $homeNumber;
        }
    
        public function getCourseLetter()
        {
            $homeLetter = '';
            foreach ($this->_data['crosslistings'] as $crosslisting) {
                if ($crosslisting['type'] != 'home listing') {
                    continue;
                }
                $homeLetter = $crosslisting['courseLetter'];
            }
            return $homeLetter;
        }
    
        public function getTitle()
        {
        	return $this->_data['title'];
        }
    
        public function setTitle($title)
        {
            $this->_data['title'] = $title;
        }
        
    
        /**
         * Used when displaying the course code as if the home subject were something else
         * ie: MATH 340 (CSCE 340) instead of CSCE 340 (MATH 340)
         * @var unknown_type
         */
        protected $_effectiveHomeSubject = '';
        
        public function setEffectiveHomeSubject($subject)
        {
            $this->_effectiveHomeSubject = $subject;
        }
        
    	public function getCourseCode()
    	{
    		$courseCode = '';
    		if (   in_array('Classroom', $this->getDeliveryMethods())
    		    || in_array('Web',       $this->getDeliveryMethods())) {
    
                $courseNumbers = array();
    		    foreach ($this->_data['crosslistings'] as $crosslisting) {
    	            if (!$this->_isEffectiveHomeCrosslisting($crosslisting)) {
    	                continue;
    	            }
    	            $homeSubject = $crosslisting['subject'];
    	            $courseNumbers[] = $crosslisting['courseNumber'] . $crosslisting['courseLetter'];
    	        }
    	        foreach ($this->_data['crosslistings'] as $crosslisting) {
    	            if ($this->_isEffectiveHomeCrosslisting($crosslisting)) {
    	                continue;
    	            }
    	            if ($crosslisting['subject'] != $homeSubject) {
    	            	continue;
    	            }
    	            $courseNumbers[] = $crosslisting['courseNumber'] . $crosslisting['courseLetter'];
    	        }
    
                sort($courseNumbers);
                if ($courseCode) {
                    $courseCode .= '/';
                }
    	        $courseCode .= implode('/', $courseNumbers);
    		}
    		if (in_array('Correspondence', $this->getDeliveryMethods())) {
                $courseNumbers = array();
                foreach ($this->_data['crosslistings'] as $crosslisting) {
                    if (!$this->_isEffectiveHomeCrosslisting($crosslisting)) {
                        continue;
                    }
                    $homeSubject = $crosslisting['subject'];
                    $courseNumbers[] = $crosslisting['courseNumber'] . $crosslisting['courseLetter'];
                }
                foreach ($this->_data['crosslistings'] as $crosslisting) {
                    if ($this->_isEffectiveHomeCrosslisting($crosslisting)) {
                        continue;
                    }
                    if ($crosslisting['subject'] != $homeSubject) {
                        continue;
                    }
                    $courseNumbers[] = $crosslisting['courseNumber'] . $crosslisting['courseLetter'] . 'x';
                }
    
                sort($courseNumbers);
                if ($courseCode) {
                	$courseCode .= '/';
                }
                $courseCode .= '[' . implode('/', $courseNumbers) . ']';
    		}
    
            return $homeSubject . ' ' . $courseCode;
    	}
    	
    	protected function _isEffectiveHomeCrosslisting($crosslisting)
    	{
    		if (!$this->_effectiveHomeSubject && $crosslisting['type'] == 'home listing' || $this->_effectiveHomeSubject == $crosslisting['subject']) {
    			return true;
    		}
    		return false;
    	}
    	
    	public function setCourseCode($subject, $courseNumber, $courseLetter = null)
    	{
            if (!self::isSubjectValid($subject)) {
                throw new Zend_Exception('The subject code ' . $subject . ' is invalid.');
            }
    
    		$homeIndex = null;
    		foreach ($this->_data['crosslistings'] as $index => $crosslisting) {
    			if ($crosslisting['type'] == 'home listing') {
    				$homeIndex = $index;
    			}
    		}
    		$homeCourseCode = array(
    		    'type'         => 'home listing',
                'subject'      => $subject,
                'courseNumber' => Zend_Filter::filterStatic($courseNumber, 'Int'),
    		    'courseLetter' => $courseLetter
    		);
    
    		if ($homeIndex !== null) {
                $this->_data['crosslistings'][$homeIndex] = $homeCourseCode;
    		} else {
    			$this->_data['crosslistings'][] = $homeCourseCode;
    		}
    	}
    
        public function getDepartment()
        {
            $homeDepartment = '';
            foreach ($this->_data['crosslistings'] as $crosslisting) {
                if ($crosslisting['type'] != 'home listing') {
                    continue;
                }
                $homeDepartment = $crosslisting['department'];
            }
            return $homeDepartment;
        }
    
        static public function getDepartments()
        {
            if (count(self::$_departments) == 0) {
                $db = Zend_Registry::get('db');
                $select = new Zend_Db_Select($db);
                $select->from(array('d' => 'creqDepartments'));
                $select->order('name');
                $records = $select->query()->fetchAll();
                $departments = array();
                foreach ($records as $record) {
                    $departments[$record['departmentId']] = $record['name'];
                }
                self::$_departments = $departments;
            }
            return self::$_departments;
        }
    
    
        public function getCollege()
        {
            $homeCollege = '';
            foreach ($this->_data['crosslistings'] as $crosslisting) {
                if ($crosslisting['type'] != 'home listing') {
                    continue;
                }
                $homeCollege = $crosslisting['college'];
            }
            return $homeCollege;
        }
        
        public function getCollegeLong()
        {
            $homeCollege = '';
            foreach ($this->_data['crosslistings'] as $crosslisting) {
                if ($crosslisting['type'] != 'home listing') {
                    continue;
                }
                $homeCollege = $crosslisting['collegeLong'];
            }
            return $homeCollege;
        }
    
        static public function getColleges()
        {
            if (count(self::$_colleges) == 0) {
                $db = Zend_Registry::get('db');
                $select = new Zend_Db_Select($db);
                $select->from(array('c' => 'creqColleges'));
                $select->order('name');
                $records = $select->query()->fetchAll();
                $colleges = array();
                foreach ($records as $record) {
                    $colleges[$record['collegeId']] = $record['name'];
                }
                self::$_colleges = $colleges;
            }
            return self::$_colleges;
        }
    
        static public function getCollegeNames()
        {
            if (count(self::$_collegeNames) == 0) {
                $db = Zend_Registry::get('db');
                $select = new Zend_Db_Select($db);
                $select->from(array('c' => 'creqColleges'));
                $select->order('description');
                $records = $select->query()->fetchAll();
                $colleges = array();
                foreach ($records as $record) {
                    $colleges[$record['collegeId']] = $record['description'];
                }
                self::$_collegeNames = $colleges;
            }
            return self::$_collegeNames;
        }
    
        public function isIntegratedStudies()
        {
        	$integratedStudies = false;
        	foreach ($this->_data['crosslistings'] as $crosslisting) {
        		if ($crosslisting['integratedStudies'] == 'yes') {
        			$integratedStudies = true;
        		}
        	}
        	return $integratedStudies;
        }
    
        public function isEssentialStudies()
        {
        	if (count($this->_data['esDesignations']) > 0) {
        		return true;
        	} else {
        		return false;
        	}
        }
        
        public function getEssentialStudiesAreas($collegeId = null)
        {
        	$areas = array();
        	foreach ((array) $this->_data['esDesignations'] as $esDesignation) {
                if (!$collegeId || $collegeId == $esDesignation['college']) {
                	$areas[$esDesignation['area']] = $esDesignation['area'];
                }
        	}
        	return $areas;
        }
    
        public function getDeliveryMethods()
        {
        	return $this->_data['deliveryMethods'];
        }
    
        public function setDeliveryMethods($deliveryMethod)
        {
        	$this->_data['deliveryMethods'] = (array) $deliveryMethod;
        }
    
        public function getCrosslistings()
        {
        	return $this->_data['crosslistings'];
        }
    
        public function getCrosslistingsText()
        {
        	$homeSubject = $this->getSubject();
    
        	$crosslistings = array();
            foreach ($this->_data['crosslistings'] as $crosslisting) {
            	if ($crosslisting['subject'] == $homeSubject) {
            		continue;
            	}
            	$crosslistings[$crosslisting['subject']][] = $crosslisting['courseNumber'] . $crosslisting['courseLetter'];
            }
            $subjects = array_keys($crosslistings);
            sort($subjects);
            $output = array();
            foreach ($subjects as $subject) {
            	$courseCodes = $crosslistings[$subject];
            	sort($courseCodes);
            	$output[] = $subject . ' ' . implode('/', $courseCodes);
            }
            $output = implode(', ', $output);
            return $output;
        }
    
        public function addCrosslisting($type, $subject, $courseNumber, $courseLetter)
        {
        	if (!self::isSubjectValid($subject)) {
        		throw new Zend_Exception('The subject code ' . $subject . ' is invalid.');
        	}
    
            $lowestId = min(array_keys($this->_data['crosslistings']));
            if (!($lowestId < 0)) {
            	$lowestId = 0;
            }
            $lowestId--;
    
            $newCrosslisting = array(
                'type'         => $type,
                'subject'      => $subject,
                'courseNumber' => Zend_Filter::filterStatic($courseNumber, 'Int'),
                'courseLetter' => $courseLetter
            );
            $this->_data['crosslistings'][$lowestId] = $newCrosslisting;
        }
    
        public function editCrosslisting($id, $type, $subject, $courseNumber, $courseLetter)
        {
            if (!self::isSubjectValid($subject)) {
                throw new Zend_Exception('The subject code ' . $subject . ' is invalid.');
            }
    
            if (!$this->_data['crosslistings'][$id]) {
            	throw new Exception('Attempt to edit a non-existant crosslisting');
            }
    
            $this->_data['crosslistings'][$id]['type'] = $type;
            $this->_data['crosslistings'][$id]['subject'] = $subject;
            $this->_data['crosslistings'][$id]['courseNumber'] = Zend_Filter::filterStatic($courseNumber, 'Int');
            $this->_data['crosslistings'][$id]['courseLetter'] = $courseLetter;
        }
    
        public function removeCrosslisting($id)
        {
            unset($this->_data['crosslistings'][$id]);
        }
    
        public function getGradTieIn()
        {
        	return $this->_data['gradTieIn'];
        }
    
        public function setGradTieIn($credits, $prerequisites, $notes)
        {
        	if (!is_array($this->_data['gradTieIn'])) {
        		$this->_data['gradTieIn'] = array();
        	}
            $this->_data['gradTieIn']['credits'] = $credits;
            $this->_data['gradTieIn']['prerequisites'] = $prerequisites;
            $this->_data['gradTieIn']['notes'] = $notes;
        }
    
        public function removeGradTieIn()
        {
            unset($this->_data['gradTieIn']);
        }
    
        public function getCredits($type = 0, $asArray = false)
        {
        	if ($type == 0) {
        		return $this->_data['credits'];
        	}
    
        	$credits = array();
        	$creditsText = array();
        	foreach ($this->_data['credits'] as $index => $credit) {
        		if ($credit['type'] == $type) {
        			$credits[$index] = $credit;
        			$creditsText[] = $credit['hours'];
        		}
        	}
    
        	if ($type != self::CREDIT_TYPE_SINGLE || !$asArray) {
        		return implode(', ', $creditsText);
        	}
    
        	return $credits;
        }
    
        public function setCredit($type, $hours)
        {
        	if (count($this->_data['credits']) > 0) {
                $lowestId = min(array_keys($this->_data['credits']));
        	} else {
        		$lowestId = 0;
        	}
            if (!($lowestId < 0)) {
                $lowestId = 0;
            }
            $lowestId--;
    
        	if ($type == self::CREDIT_TYPE_SINGLE) {
        		foreach ($hours as $key => $hour) {
        			if (!Zend_Validate::is($hour, 'Int')) {
        				unset($hours[$key]);
        			}
        		}
    
        		foreach ($this->_data['credits'] as $key => $credit) {
        			if ($credit['type'] == $type) {
        				if (count($hours) == 0) {
        					unset($this->_data['credits'][$key]);
        				} else {
        				    $this->_data['credits'][$key]['hours'] = array_pop($hours);
        				}
        			}
        		}
    
        		while (count($hours) > 0) {
    		        $newCredit = array(
    		            'type' => $type,
    		            'hours' => array_pop($hours)
    		        );
    
    		        $this->_data['credits'][$lowestId] = $newCredit;
    		        $lowestId--;
        		}
    
        		return;
        	}
    
        	$found = false;
        	foreach ($this->_data['credits'] as $key => $credit)
        	{
                if ($credit['type'] == $type) {
                	if (!Zend_Validate::is($hours, 'Int')) {
                		unset($this->_data['credits'][$key]);
                	} else {
                	    $this->_data['credits'][$key]['hours'] = $hours;
                	}
                    $found = true;
                }
        	}
        	if ($found || !Zend_Validate::is($hours, 'Int')) {
        		return;
        	}
    
        	$newCredit = array(
                'type' => $type,
                'hours' => $hours
        	);
    
        	$this->_data['credits'][$lowestId] = $newCredit;
    
        }
    
        public function getCreditsText()
        {
            $singleCredits = array();
            $minRange = '';
            $maxRange = '';
            $maxSemester = '';
            $maxMajor = '';
            foreach($this->_data['credits'] as $credit) {
                if($credit['type'] == 1) {
                    $singleCredits[] = $credit['hours'];
                } else if($credit['type'] == 2) {
                    $minRange = $credit['hours'];
                } else if($credit['type'] == 3) {
                    $maxRange = $credit['hours'];
                } else if($credit['type'] == 4) {
                    $maxSemester = $credit['hours'];
                } else if($credit['type'] == 5) {
                    $maxMajor = $credit['hours'];
                }
            }
            $creditListings = array();
            if(count($singleCredits) > 0) {
                $creditListings[] = implode(' or ', $singleCredits) . ' cr';
            }
            if($minRange != '' && $maxRange != '') {
                $creditListings[] = $minRange . '-' . $maxRange . ' cr';
            }
            if($maxSemester != '') {
                $creditListings[] = $maxSemester . ' cr per sem';
            }
            if($maxMajor != '') {
                $creditListings[] = 'max ' . $maxMajor;
            }
    
            if(count($this->_data['termsOffered']) > 0 && count($this->_data['termsOffered']) < 3) {
                $termsOffered = implode(', ', $this->_data['termsOffered']);
                $termsOffered = strtr($termsOffered, array('Fall' => 'I', 'Spring' => 'II', 'Summer' => 'III'));
            }
    
            if(count($creditListings) > 0) {
                $credits = '(' . implode(', ', $creditListings);
                if($termsOffered != '') {
                    $credits .= ' ' . $termsOffered;
                }
                $credits .= ')';
            } else if($termsOffered != '') {
                $credits = '(' . $termsOffered . ')';
            }
    
            return $credits;
        }
    
        public function getTermsOffered()
        {
        	return $this->_data['termsOffered'];
        }
    
        public function setTermsOffered($terms)
        {
            $this->_data['termsOffered'] = (array) $terms;
        }
    
        public function getCampuses()
        {
            return $this->_data['campuses'];
        }
    
        public function setCampuses($campuses)
        {
        	$this->_data['campuses'] = (array) $campuses;
        }
    
        public function getGradingType()
        {
        	return $this->_data['gradingType'];
        }
    
        public function setGradingType($gradingType)
        {
        	$this->_data['gradingType'] = $gradingType;
        }
    
        public function getDfRemoval()
        {
        	return $this->_data['dfRemoval'];
        }
    
        public function setDfRemoval($dfRemoval)
        {
        	$this->_data['dfRemoval'] = $dfRemoval;
        }
    
        public function getActivities()
        {
        	return $this->_data['activities'];
        }
    
        public function getActivityText()
        {
        	$activityMap = self::_getActivityMap();
        	$activityMap = array_flip($activityMap);
    
            $activityListing = array();
            foreach($this->_data['activities'] as $activity) {
                $newActivityListing = $activity['type'];
                if($activity['hours'] != '') {
                    $newActivityListing .= ' ' . $activity['hours'];
                }
                $activityId = $activityMap[$activity['type']];
                $activityListing[$activityId] = $newActivityListing;
            }
            ksort($activityListing);
            if(count($activityListing) > 0) {
                $activities = ucfirst(implode(', ', $activityListing) . '.');
            }
    
            return $activities;
        }
    
        static protected function _getActivityMap()
        {
        	if (!self::$_activityMap) {
        		self::_loadActivityMap();
        	}
        	return self::$_activityMap;
        }
    
        static protected function _loadActivityMap()
        {
        	$db = Zend_Registry::get('db');
        	$select = new Zend_Db_Select($db);
        	$select->from('creqActivityTypes');
        	$data = $select->query()->fetchAll();
    
        	foreach ($data as $row) {
        		self::$_activityMap[$row['activityTypeId']] = $row['shortName'];
        	}
        }
    
        public function setActivity($type, $hours = null)
        {
            if ($type < 0) {
                return;
            }
            
        	if ($hours == '') {
        		$hours = null;
        	}
    
        	$found = false;
            foreach ($this->_data['activities'] as $id => $activity) {
            	if ($activity['type'] == $type) {
            		$this->_data['activities'][$id]['hours'] = $hours;
            		$found = true;
            	}
            }
            if ($found) {
            	return;
            }
    
            $lowestId = min(array_keys($this->_data['activities']));
            if (!($lowestId < 0)) {
                $lowestId = 0;
            }
            $lowestId--;
    
            $newActivity = array(
                'type' => $type,
                'hours' => $hours
            );
            $this->_data['activities'][$lowestId] = $newActivity;
        }
    
        public function removeActivity($type)
        {
        	foreach ($this->_data['activities'] as $id => $activity) {
        		if ($activity['type'] == $type) {
        			unset($this->_data['activities'][$id]);
        		}
        	}
        }
    
        public function getPrerequisite()
        {
        	return $this->_data['prerequisite'];
        }
    
        public function setPrerequisite($prerequisite)
        {
            $this->_data['prerequisite'] = $prerequisite;
        }
    
        public function getNotes()
        {
        	return $this->_data['notes'];
        }
    
        public function setNotes($notes)
        {
        	$this->_data['notes'] = $notes;
        }
    
        public function getDescription()
        {
        	return $this->_data['description'];
        }
    
        public function setDescription($description)
        {
            $this->_data['description'] = $description;
        }
    
        public function isAce()
        {
            if (count($this->getAceOutcomes()) > 0) {
                return true;
            }
            
            return false;
        }
        
        public function getAceOutcomes()
        {
            if (!is_array($this->_data['aceOutcomes'])) {
                return array();
            }
    
        	$outcomes = $this->_data['aceOutcomes'];
        	foreach ($outcomes as $key => $outcome)
        	{
        		$shortNameToSlo = array_flip(self::$_outcomeShortNames);
        		$slo = $shortNameToSlo[$outcome['name']];
        		$outcomes[$key]['slo'] = $slo;
        		$outcomes[$key]['description'] = self::$_outcomeDescriptions[$slo];
        	}
        	return $outcomes;
        }
    
        public function getAceOutcomeDataWithSloKey()
        {
        	$data = array();
            foreach (self::$_outcomeShortNames as $key => $shortName) {
                $data[$key] = array('shortName' => $shortName,
                                    'description' => self::$_outcomeDescriptions[$key]);
            }
            return $data;
        }
    
        public function getAceOutcomeByShortName($shortName)
        {
        	$return = null;
        	if (Unl_Util::isArray($this->_data['aceOutcomes'])) {
            	foreach ($this->_data['aceOutcomes'] as $aceOutcome) {
                    if ($aceOutcome['name'] == $shortName) {
                    	$return = $aceOutcome;
                    }
            	}
        	}
        	return $return;
        }
    
        public function setAceOutcome($name, $justification, $studentWork, $assessmentPlan)
        {
        	$found = false;
            if (!is_array($this->_data['aceOutcomes'])) {
                $this->_data['aceOutcomes'] = array();
            }
            foreach ($this->_data['aceOutcomes'] as $id => $aceOutcome) {
            	if ($aceOutcome['name'] == $name) {
                    $this->_data['aceOutcomes'][$id]['justification'] = $justification;
                    $this->_data['aceOutcomes'][$id]['studentWork'] = $studentWork;
                    $this->_data['aceOutcomes'][$id]['assesmentPlan'] = $assessmentPlan;
            		$found = true;
            	}
            }
    
            if ($found) {
            	return;
            }
    
            $lowestId = min(array_keys($this->_data['aceOutcomes']));
            if (!($lowestId < 0)) {
                $lowestId = 0;
            }
            $lowestId--;
    
            $newAceOutcome = array(
                'name'          => $name,
                'justification' => $justification,
                'studentWork'   => $studentWork,
                'assesmentPlan' => $assessmentPlan
            );
    
            $this->_data['aceOutcomes'][$lowestId] = $newAceOutcome;
        }
    
        public function removeAceOutcome($name)
        {
        	if (!is_array($this->_data['aceOutcomes'])) {
        		return;
        	}
    
        	foreach ($this->_data['aceOutcomes'] as $id => $aceOutcome) {
        		if ($aceOutcome['name'] == $name) {
        			unset($this->_data['aceOutcomes'][$id]);
        		}
        	}
        }
        
        public function getAceReinforcements()
        {
        	$reinforcements = $this->_data['aceReinforcements'];
        	foreach ($reinforcements as $key => $reinforcement) {
        		$reinforcements[$key]['longName'] = self::$_reinforcementNames[$reinforcement['name']];
        	}
        	return $reinforcements;
        }
    
        public function getAceReinforcementNames()
        {
            return self::$_reinforcementNames;
        }
    
        public function getAceReinforcementByShortName($shortName)
        {
            $return = null;
        	if (Unl_Util::isArray($this->_data['aceReinforcements'])) {
                foreach ($this->_data['aceReinforcements'] as $aceReinforcement) {
                    if ($aceReinforcement['name'] == $shortName) {
                        $return = $aceReinforcement;
                    }
                }
        	}
            return $return;
        }
    
        public function setAceReinforcement($name, $description)
        {
            $found = false;
    
            if (!is_array($this->_data['aceReinforcements'])) {
                $this->_data['aceReinforcements'] = array();
            }
    
            foreach ($this->_data['aceReinforcements'] as $id => $aceReinforcement) {
                if ($aceReinforcement['name'] == $name) {
                    $this->_data['aceReinforcements'][$id]['description'] = $description;
                    $found = true;
                }
            }
    
            if ($found) {
                return;
            }
    
            $lowestId = min(array_keys($this->_data['aceReinforcements']));
            if (!($lowestId < 0)) {
                $lowestId = 0;
            }
            $lowestId--;
    
            $newAceReinforcement = array(
                'name'        => $name,
                'description' => $description
            );
    
            $this->_data['aceReinforcements'][$lowestId] = $newAceReinforcement;
        }
    
        public function removeAceReinforcement($name)
        {
            if (!is_array($this->_data['aceReinforcements'])) {
                return;
            }
    
            foreach ($this->_data['aceReinforcements'] as $id => $aceReinforcement) {
                if ($aceReinforcement['name'] == $name) {
                    unset($this->_data['aceReinforcements'][$id]);
                }
            }
        }
    
        public function removeAce()
        {
            $this->_data['aceOutcomes'] = array();
            $this->_data['aceReinforcements'] = array();
        }
        
        public function getEffectiveSemester()
        {
            return $this->_data['effectiveSemester'];
        }
        
        public function getEffectiveSemesterDescription()
        {
        	$year = substr($this->_data['effectiveSemester'], 0, 4);
        	$term = substr($this->_data['effectiveSemester'], 4);
        	$termDescriptions = array(1 => 'Fall', 'Spring', 'Summer');
        	if ($term == 1) {
        		$year--;
        	}
        	$term = $termDescriptions[$term];
        	
        	return $term . ' ' . $year . ' (' . substr($this->_data['effectiveSemester'], 2) . ')';
        }
    
        public function setEffectiveSemester($semester)
        {
            $this->_data['effectiveSemester'] = $semester;
        }
    
        public function getRequest()
        {
            return $this->_data['request'];
        }
    
        public function setRequest(Requests_RequestModel $request)
        {
            $this->_data['request'] = $request->getId();
        }
    
        public function clearRequest()
        {
        	$this->_data['request'] = null;
        }
    
        public function getType()
        {
            return $this->_data['type'];
        }
    
        public function setType($type)
        {
            $this->_data['type'] = $type;
        }
    
        public function getRemoved()
        {
        	if ($this->_data['removed'] == 'yes') {
        		return true;
        	}
        	return false;
        }
    
        public function setRemoved($removed = true)
        {
        	if ($removed) {
        		$this->_data['removed'] = 'yes';
        	} else {
                $this->_data['removed'] = 'no';
        	}
        }
    
        public function getCourseId()
        {
            return $this->_data['course'];
        }
        
        public function getParentId()
        {
            return $this->_data['parent'];
        }
    
        public function isValid()
        {
        	//TODO: add criteria for this being valid
        	if (!$this->getGradingType()) {
        		return false;
        	}
        	return true;
        }
    
        static $_subjectList;
        static $_subjectNames;
    
        static protected function _loadSubjectList()
        {
        	if (self::$_subjectList) {
        		return self::$_subjectList;
        	}
    
        	$db = Zend_Registry::get('db');
        	$select = new Zend_Db_Select($db);
    
        	$select->from('creqSubjects', array('subjectId', 'name', 'description'));
        	$select->order('name');
        	$records = $select->query()->fetchAll();
        	self::$_subjectList = array();
        	foreach ($records as $record) {
        		self::$_subjectList[$record['subjectId']] = $record['name'];
        		self::$_subjectNames[$record['subjectId']] = $record['description'];
        	}
    
        	return self::$_subjectList;
        }
    
        static public function isSubjectValid($subject)
        {
        	self::_loadSubjectList();
    
        	return in_array($subject, self::$_subjectList);
        }
    
        static public function makeCurrent($courseModels)
        {
            if (!Unl_Util::isArray($courseModels)) {
            	if (!($courseModels instanceof self)) {
                    throw Exception(__CLASS__ . '::' . __METHOD__ . '(): invalid argument.');
            	}
            	$collection = new Unl_Model_Collection(__CLASS__);
            	$collection[] = $courseModels;
            	$courseModels = $collection;
            }
    
            if (count($courseModels) == 0) {
            	return;
            }
    
            $courseOfficialGenerations = array();
            foreach ($courseModels as $courseModel) {
            	$courseId = $courseModel->_data['course'];
            	$generationId = $courseModel->getId();
            	$courseOfficialGenerations[$courseId] = $generationId;
            }
    
    
    
            $db = Zend_Registry::get('db');
    
            $sql = 'CREATE TEMPORARY TABLE creqCoursesUpdate '
                 . 'SELECT * FROM creqCourses LIMIT 0';
            $db->query($sql);
    
            $sql = 'INSERT INTO creqCoursesUpdate VALUES ';
            $sqlParts = array();
            foreach ($courseOfficialGenerations as $courseId => $generationId) {
                $sqlParts[] = $db->quoteInto('(?, ', $courseId)
                            . $db->quoteInto('?)'  , $generationId);
            }
            $sql .= implode(', ', $sqlParts);
            $db->query($sql);
    
            $sql = 'UPDATE creqCourses AS a, '
                 . '       creqCoursesUpdate AS b '
                 . 'SET a.currentGeneration = b.currentGeneration '
                 . 'WHERE a.courseId = b.courseId ';
    
            $db->query($sql);
            $db->query('DROP TABLE creqCoursesUpdate');
        }
    
        public function getEmptyEssentialStudiesArray(College $college = null)
        {
            $areaCodes = array('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H');
            $colleges = self::getColleges();
    
            $areas = array();
            if ($college) {
                foreach ($areaCodes as $areaCode) {
                    $areas[$areaCode] = false;
                }
            } else {
                foreach ($colleges as $collegeRow) {
                    $areas[$collegeRow->name] = array();
                    foreach ($areaCodes as $areaCode) {
                        $areas[$collegeRow->name][$areaCode] = false;
                    }
                }
            }
    
            return $areas;
        }
    
        /**
         * This function will create new generations of any courses with references to $oldCode and replace
         * them with $newCode.  All current official generations will have a new official generation created
         * the change, and all in-progress requests will have new generations created with the change.
         * This method should only be called !!ONCE!! for such a change.
         * I recommend against having this method publicly available, except when needed.
         *
         * @param string $oldCode
         * @param string $newCode
         */
        static public function updateSubjectCode($oldCode, $newCode)
        {
            $db = Zend_Registry::get('db');
            $generationIds = array();
    
            // Get current official generation with crosslistings
            $select = new Zend_Db_Select($db);
            $select->from(array('c' => 'creqCourseCodes'), array());
            $select->join(array('x' => 'creqCourseCrosslistings'), 'c.courseCodeId = x.courseCode', array('generation'));
            $select->join(array('g' => 'creqCourseGenerations'), 'x.generation = g.courseGenerationId', array('course', 'type'));
            $select->join(array('s' => 'creqCourses'), 'g.course = s.courseId', array('currentGeneration'));
            $select->where('c.subject = ?', $oldCode);
            $select->where('g.courseGenerationId = s.currentGeneration');
    
            $data = $select->query()->fetchAll();
    
            foreach ($data as $row) {
                $generationIds[] = $row['currentGeneration'];
            }
    
    
            // Get current official generation with prereq, notes, description, title
            $select = new Zend_Db_Select($db);
            $select->from(array('d' => 'creqCourseDetails'), array('prerequisite'));
            $select->join(array('g' => 'creqCourseGenerations'), 'd.generation = g.courseGenerationId', array('course', 'type'));
            $select->join(array('s' => 'creqCourses'), 'g.course = s.courseId', array('currentGeneration'));
            $select->where(
                $db->quoteInto('d.prerequisite LIKE ? OR ', '%' . $oldCode . '%') .
                $db->quoteInto('d.notes LIKE ? OR ',        '%' . $oldCode . '%') .
                $db->quoteInto('d.description LIKE ? OR ',  '%' . $oldCode . '%') .
                $db->quoteInto('d.title LIKE ?',            '%' . $oldCode . '%')
            );
    
            $data = $select->query()->fetchAll();
    
            foreach ($data as $row) {
                $generationIds[] = $row['currentGeneration'];
            }
    
    
            // Get current official generation with ace outcomes
            $select = new Zend_Db_Select($db);
            $select->from(array('d' => 'creqCourseAceOutcomes'));
            $select->join(array('g' => 'creqCourseGenerations'), 'd.generation = g.courseGenerationId', array('course', 'type'));
            $select->join(array('s' => 'creqCourses'), 'g.course = s.courseId', array('currentGeneration'));
            $select->where(
                $db->quoteInto('d.justification LIKE ? OR ', '%' . $oldCode . '%') .
                $db->quoteInto('d.studentWork LIKE ? OR ',   '%' . $oldCode . '%') .
                $db->quoteInto('d.assesmentPlan LIKE ?',     '%' . $oldCode . '%')
            );
    
    
            // Get current official generation with ace reinforcements
            $select = new Zend_Db_Select($db);
            $select->from(array('d' => 'creqCourseAceReinforcements'));
            $select->join(array('g' => 'creqCourseGenerations'), 'd.generation = g.courseGenerationId', array('course', 'type'));
            $select->join(array('s' => 'creqCourses'), 'g.course = s.courseId', array('currentGeneration'));
            $select->where(
                $db->quoteInto('d.description LIKE ?',     '%' . $oldCode . '%')
            );
    
            $data = $select->query()->fetchAll();
    
            foreach ($data as $row) {
                $generationIds[] = $row['currentGeneration'];
            }
    
    
            // Get in-progress requests with crosslistings
            $select = new Zend_Db_Select($db);
            $select->from(array('c' => 'creqCourseCodes'), array());
            $select->join(array('x' => 'creqCourseCrosslistings'), 'c.courseCodeId = x.courseCode', array('generation'));
            $select->join(array('g' => 'creqCourseGenerations'), 'x.generation = g.courseGenerationId', array('course', 'type'));
            $select->where('c.subject = ?', $oldCode);
            $select->where('g.courseGenerationId NOT IN (SELECT parent FROM creqCourseGenerations WHERE parent IS NOT NULL)');
    
            $data = $select->query()->fetchAll();
    
            foreach ($data as $row) {
                $generationIds[] = $row['generation'];
            }
    
    
            // Get in-progress requests with prereq, notes, description, title
            $select = new Zend_Db_Select($db);
            $select->from(array('d' => 'creqCourseDetails'), array('prerequisite'));
            $select->join(array('g' => 'creqCourseGenerations'), 'd.generation = g.courseGenerationId', array('course', 'type'));
            $select->where(
                $db->quoteInto('d.prerequisite LIKE ? OR ', '%' . $oldCode . '%') .
                $db->quoteInto('d.notes LIKE ? OR ',        '%' . $oldCode . '%') .
                $db->quoteInto('d.description LIKE ? OR ',  '%' . $oldCode . '%') .
                $db->quoteInto('d.title LIKE ?',            '%' . $oldCode . '%')
            );
            $select->where('g.courseGenerationId NOT IN (SELECT parent FROM creqCourseGenerations WHERE parent IS NOT NULL)');
    
            $data = $select->query()->fetchAll();
    
            foreach ($data as $row) {
                $generationIds[] = $row['generation'];
            }
    
    
            // Get in-progress requests with ace outcomes
            $select = new Zend_Db_Select($db);
            $select->from(array('d' => 'creqCourseAceOutcomes'));
            $select->join(array('g' => 'creqCourseGenerations'), 'd.generation = g.courseGenerationId', array('course', 'type'));
            $select->where(
                $db->quoteInto('d.justification LIKE ? OR ', '%' . $oldCode . '%') .
                $db->quoteInto('d.studentWork LIKE ? OR ',   '%' . $oldCode . '%') .
                $db->quoteInto('d.assesmentPlan LIKE ?',     '%' . $oldCode . '%')
            );
            $select->where('g.courseGenerationId NOT IN (SELECT parent FROM creqCourseGenerations WHERE parent IS NOT NULL)');
    
    
            // Get in-progress requests with ace reinforcements
            $select = new Zend_Db_Select($db);
            $select->from(array('d' => 'creqCourseAceReinforcements'));
            $select->join(array('g' => 'creqCourseGenerations'), 'd.generation = g.courseGenerationId', array('course', 'type'));
            $select->where(
                $db->quoteInto('d.description LIKE ?',     '%' . $oldCode . '%')
            );
            $select->where('g.courseGenerationId NOT IN (SELECT parent FROM creqCourseGenerations WHERE parent IS NOT NULL)');
    
            $data = $select->query()->fetchAll();
    
            foreach ($data as $row) {
                $generationIds[] = $row['currentGeneration'];
            }
    
    
            sort($generationIds);
            $generationIds = array_unique($generationIds);
    
            $officialGenerations = Courses_CourseModel::find($generationIds);
    
            $parentMap = array();
            foreach ($officialGenerations as $course) {
                $newCourse = clone $course;
                $newCourse->setType($course->getType());
                $crosslistings = $newCourse->getCrosslistings();
                foreach($crosslistings as $id => $x) {
                    if ($x['subject'] == $oldCode) {
                        $newCourse->editCrosslisting($id, $x['type'], $newCode, $x['courseNumber'], $x['courseLetter']);
                    }
                }
                $newCourse->setPrerequisite(strtr($newCourse->getPrerequisite(), array($oldCode => $newCode)));
                $newCourse->setNotes(strtr($newCourse->getNotes(), array($oldCode => $newCode)));
                $newCourse->setDescription(strtr($newCourse->getDescription(), array($oldCode => $newCode)));
                $newCourse->setTitle(strtr($newCourse->getTitle(), array($oldCode => $newCode)));
                $aceOutcomes = $newCourse->getAceOutcomes();
                foreach($aceOutcomes as $aceOutcome) {
                	$newCourse->setAceOutcome(
                        $aceOutcome['name'],
                        strtr($aceOutcome['justification'], array($oldCode => $newCode)),
                        strtr($aceOutcome['studentWork'], array($oldCode => $newCode)),
                        strtr($aceOutcome['assesmentPlan'], array($oldCode => $newCode))
                    );
                }
                $aceReinforcements = $newCourse->getAceReinforcements();
                foreach ($aceReinforcements as $aceReinforcement) {
                	$newCourse->setAceReinforcement(
                        $aceReinforcement['name'],
                        strtr($aceReinforcement['description'], array($oldCode => $newCode))
                    );
                }
    
                $newCourse->setEffectiveSemester('20092');
                if ($newCourse->getType() == 'official') {
                    $newCourse->clearRequest();
                }
    
                Courses_CourseModel::save($newCourse);
                $parentMap[$course->getId()] = $newCourse->getId();
            }
    
            foreach ($parentMap as $oldId => $newId) {
                $sql = "UPDATE creqCourseGenerations SET parent = $newId WHERE parent = $oldId AND courseGenerationId != $newId";
                $db->query($sql);
                $sql = "UPDATE creqCourses SET currentGeneration = $newId WHERE currentGeneration = $oldId";
                $db->query($sql);
            }
        }
        
        public function getDifferenceSummary(Courses_CourseModel $original = null, Requests_RequestModel $request = null)
        {
            if (!$original || $original == $this) {
                if ($request && $request->getType() == 'NewCourseWithIS' ) {
                    return 'New Course With IS';
                } else if ($request && $request->getType() == 'NewCourseWithACE') {
                	return 'New ACE Course';
                } else {
                    return 'New Course';
                }
            }
            
            if ($this->getRemoved() && !$original->getRemoved()) {
                return 'Remove Course';
            }
            
            $summary = array();
        
            
            if ($this->getSubject() != $original->getSubject()) {
                $summary[] = 'subject code';
            }
            
            if ($this->getCourseNumber() . $this->getCourseLetter() != $original->getCourseNumber() . $original->getCourseLetter()) {
                $summary[] = '#';
            }
            
            if ($this->getTitle() != $original->getTitle()) {
                $summary[] = 'title';
            }
            
            if ($this->getCrosslistingsText() != $original->getCrosslistingsText()) {
                $summary[] = 'crosslist';
            }
            
            if ($this->getCreditsText() != $original->getCreditsText()) {
                $summary[] = 'credit';
            }
            
            if ($this->getPrerequisite() != $original->getPrerequisite()) {
                $summary[] = 'prereq';
            }
        
            if ($this->getDescription() != $original->getDescription()) {
                $summary[] = 'descrip';
            }
        
            if ($this->getNotes() != $original->getNotes()) {
                $summary[] = 'note';
            }
            
            $myGradTieIn = $this->getGradTieIn();
            $originalGradTieIn = $original->getGradTieIn();
            if ($myGradTieIn['credits'] != $originalGradTieIn['credits'] ||
                $myGradTieIn['notes'] != $originalGradTieIn['notes'] ||
                $myGradTieIn['prerequisites'] != $originalGradTieIn['prerequisites']) {
                $summary[] = 'grad tie-in';
            }
            
            $currentAce = array();
            foreach ($this->getAceOutcomes() as $aceOutcome) {
                $currentAce[] = substr($aceOutcome['slo'], 3);
            }
            $originalAce = array();
            foreach ($original->getAceOutcomes() as $aceOutcome) {
                $originalAce[] = substr($aceOutcome['slo'], 3);
            }
            
            if ($currentAce != $originalAce) {
            	$aceNumbers = array_diff($originalAce, $currentAce)
            	            + array_diff($currentAce, $originalAce);
                $summary[] = 'ace ' . implode(',', $aceNumbers);
            }
            
            if ($this->getDeliveryMethods() != $original->getDeliveryMethods()) {
                $summary[] = 'delivery';
            }
            
            if ($this->getTermsOffered() != $original->getTermsOffered()) {
                $summary[] = 'terms';
            }
            
            if ($this->getCampuses() != $original->getCampuses()) {
                $summary[] = 'campuses';
            }
            
            if ($this->getGradingType() != $original->getGradingType()) {
                $summary[] = 'grading type';
            }
            
            if ($this->getActivityText() != $original->getActivityText()) {
                $summary[] = 'activity';
            }
            
            if ($request && $request->getType() == 'AddISToCourse') {
                $summary[] = 'IS';
            }
            
            
            
            
            
            
            $summary = implode('/', $summary);
            $summary = ucfirst($summary);
            return $summary;
        }
    }