diff --git a/inc/class.schedule.php b/inc/class.schedule.php
new file mode 100755
--- /dev/null
+++ b/inc/class.schedule.php
@@ -0,0 +1,569 @@
+.
+ */
+
+//**************************************************
+// class.schedule.php Author: Nathan Gelderloos
+//
+// Represents a schedule of a week. Stores the
+// classes that are part of that week and calculates
+// all the possible permutations.
+//**************************************************
+
+include_once('inc/class.course.inc');
+include_once 'class.section.php';
+include_once 'inc/class.page.php';
+
+/*
+ * Load a Classes -> Course converter class for the sake of the
+ * Schedule::__wakeup() magic function.
+ */
+require_once('inc/class.classes_convert.inc');
+
+class Schedule
+{
+ /*
+ * Variables for upgrading from saved schedules created when there
+ * was a class called Classes.
+ */
+ private $classStorage; // array of courses
+ private $nclasses; // Integer number of classes
+
+ /* My member variables. */
+ private $courses;
+ private $nPermutations = 0; // Integer number of real permutations
+ private $possiblePermutations; // Integer number of possible permutations
+ private $scheduleName; // String name of schedule
+ private $storage; // Integer array of valid schedules
+ private $title;
+
+ /**
+ * \brief
+ * My global identification number. Not defined until the schedule
+ * is processed and first saved.
+ */
+ private $id;
+ /**
+ * The input format of the sections. Only used for the UI. Valid
+ * values are 'numerous' for custom, 'numbered' for numeric, and 'lettered' for
+ * alphabetical.
+ */
+ public $section_format;
+
+ /**
+ * \brief
+ * Create a schedule with the given name.
+ */
+ function __construct($name)
+ {
+ $this->courses = array();
+ $this->scheduleName = $name;
+ $this->storage = array();
+ $this->title = "SlatePermutate - Scheduler";
+ $this->section_format = 'numerous';
+
+ /* mark this as an upgraded Schedule class. See __wakeup() */
+ $this->nclasses = -1;
+ }
+
+ //--------------------------------------------------
+ // Mutators and Accessors
+ //--------------------------------------------------
+ public function getName()
+ {
+ return $this->scheduleName;
+ }
+
+ //--------------------------------------------------
+ // Adds a new class to the schedule.
+ //--------------------------------------------------
+ function addCourse($n)
+ {
+ $this->courses[] = new Course($n);
+ }
+
+ //--------------------------------------------------
+ // Adds a section to the desired class.
+ //--------------------------------------------------
+ function addSection($course_name, $letter, $time_start, $time_end, $days, $synonym = NULL, $faculty = NULL, $location = NULL, $type = 'lecture')
+ {
+ $found = false;
+ $counter = 0;
+
+ foreach ($this->courses as $course)
+ if (!strcmp($course_name, $course->getName()))
+ {
+ $section = $course->section_get($letter);
+ if (!$section)
+ {
+ $section = new Section($letter, array(), $synonym, $faculty);
+ $course->section_add($section);
+ }
+ $section->meeting_add(new SectionMeeting($days, $time_start, $time_end, $location, $type));
+
+ return;
+ }
+
+ echo 'Could not find class: ' . $course_name . "
\n";
+ }
+
+ //--------------------------------------------------
+ // Finds all of the possible permutations and stores
+ // the results in the storage array.
+ //--------------------------------------------------
+ function findPossibilities()
+ {
+ $this->possiblePermutations = 1;
+ /* special case: there is nothing entered into the schedule and thus there is one, NULL permutation */
+ if (!count($this->courses))
+ {
+ /* have an empty schedule */
+ $this->nPermutations = 1;
+ return;
+ }
+
+ $position = 0;
+ $counter = 0;
+
+ $i = 0;
+ foreach ($this->courses as $course)
+ {
+ $this->possiblePermutations = $this->possiblePermutations * $course->getnsections();
+ $cs[$i] = 0; // Sets the counter array to all zeroes.
+ $i ++;
+ }
+
+ // Checks for conflicts in given classes, stores if none found
+ do
+ {
+ $conflict = false;
+
+ // Get first class to compare
+ for ($upCounter = 0; $upCounter < count($this->courses) && !$conflict; $upCounter ++)
+ {
+
+ for ($downCounter = count($this->courses) - 1; $downCounter > $upCounter && !$conflict; $downCounter --)
+ {
+ if ($this->courses[$upCounter]->getSection($cs[$upCounter])
+ ->conflictsWith($this->courses[$downCounter]->getSection($cs[$downCounter])))
+ {
+ $conflict = TRUE;
+ break;
+ }
+ }
+ }
+
+ // Store to storage if no conflict is found.
+ if(!$conflict)
+ {
+ for($i = 0; $i < count($this->courses); $i++)
+ {
+ $this->storage[$this->nPermutations][$i] = $cs[$i];
+ }
+ $this->nPermutations++;
+ }
+
+ // Increase the counter by one to get the next combination of class sections.
+ $cs[$position] = $cs[$position] + 1;
+
+ // Check to make sure the counter is still valid.
+ $valid = false;
+ while(!$valid)
+ {
+ if($cs[$position] == $this->courses[$position]->getnsections())
+ {
+ $cs[$position] = 0;
+
+ $position++;
+
+ // This is for the very last permutation. Even
+ // though the combination is not actually true
+ // the larger while loop will end before any
+ // new combinations are performed.
+ if($position == count($this->courses))
+ {
+ $valid = true;
+ } else {
+ $cs[$position]++;
+ }
+ } else {
+ $valid = true;
+ $position = 0;
+ }
+ }
+
+ $counter++;
+ } while($counter < $this->possiblePermutations);
+ }
+
+ //--------------------------------------------------
+ // Prints out the possible permutations in tables.
+ //--------------------------------------------------
+ function writeoutTables()
+ {
+ $filled = false;
+ $time = array(700,730,800,830,900,930,1000,1030,1100,1130,1200,1230,1300,1330,1400,1430,1500,1530,1600,1630,1700,1730,1800,1830,1900,1930,2000,2030,2100,2130, 2200);
+
+ define('SP_PERMUTATIONS_PER_PAGE', 256); /** @TODO: Define this in config.inc */
+
+ $npages = ceil($this->nPermutations / SP_PERMUTATIONS_PER_PAGE);
+ $page = 0;
+ if (isset($_REQUEST['page']))
+ $page = $_REQUEST['page'];
+ /*
+ * only display the ``this page doesn't exist'' 404 if there is at
+ * least one permutation. Otherwise, we give an irrelevant 404 for
+ * users with no permutations.
+ */
+ if ($this->nPermutations && $page >= $npages)
+ Page::show_404('Unable to find page ' . $page . ', there are only ' . $this->nPermutations . ' non-conflicting permutations, for a total of ' . $npages . ' pages.');
+ /* zero-based */
+ $first_permutation = $page * SP_PERMUTATIONS_PER_PAGE;
+ $last_permutation = min($this->nPermutations, $first_permutation + SP_PERMUTATIONS_PER_PAGE);
+
+ $footcloser = '';
+
+ if(isset($_REQUEST['print']) && $_REQUEST['print'] != ''){
+ $headcode = array('jQuery', 'jQueryUI', 'uiTabsKeyboard', 'outputStyle', 'outputPrintStyle', 'displayTables');
+ }
+ else {
+ $headcode = array('outputStyle', 'jQuery', 'jQueryUI', 'uiTabsKeyboard', 'displayTables');
+ }
+ $outputPage = new Page(htmlentities($this->getName()), $headcode);
+
+
+
+ if(isset($_REQUEST['print'])) {
+
+ echo '';
+
+ echo '
Having problems? Let us know.
'; + echo 'Keyboard Shortcut: Left and right arrow keys switch between schedules
'; + } + + echo "\n"; + + if($this->nPermutations > 0) + { + + echo 'Enter these codes into your school\'s online course registration system to register for classes:
| ' . ($i + 1) . " | \n" + . "Monday | \n" + . "Tuesday | \n" + . "Wednesday | \n" + . "Thursday | \n" + . "Friday | \n" + . "
| " . $this->prettyTime($time[$r]) . " | \n"; + + for($dayLoop = 0; $dayLoop < 5; $dayLoop++) + { + /* Makes sure there is not a class already in progress */ + if($rowspan[$dayLoop] <= 0) + { + for($j = 0; $j < count($this->courses); $j++) + { + $class = $this->courses[$j]; + $section_index = $this->storage[$i][$j]; + $section = $class->getSection($section_index); + /* iterate through all of a class's meeting times */ + $meetings = $section->getMeetings(); + + /* find any meeting which are going on at this time */ + $current_meeting = NULL; + foreach ($meetings as $meeting) + { + if ($meeting->getDay($dayLoop) + && $meeting->getStartTime() >= $time[$r] + && $meeting->getStartTime() < $time[$r+1]) + { + $current_meeting = $meeting; + } + } + + if ($current_meeting) + { + /* calculate how many rows this section should span */ + for ($my_r = $r; $current_meeting->getEndTime() > $time[$my_r]; $my_r ++) + ; + $rowspan[$dayLoop] = $my_r - $r; + + $single_multi = 'single'; + if ($rowspan[$dayLoop] > 1) + $single_multi = 'multi'; + + echo '' + . htmlentities($class->getName(), ENT_QUOTES) . '-' + . htmlentities($section->getLetter(), ENT_QUOTES) . "\n" + . '' . htmlentities($section->getProf(), ENT_QUOTES) . "\n" + . '' . htmlentities($current_meeting->getLocation(), ENT_QUOTES) . "\n" + . '' . htmlentities($section->getSynonym(), ENT_QUOTES) . "\n" + . " | \n"; + $syns[$section->getSynonym()] = $section->getSynonym(); + $filled = TRUE; + } + } + } + + if ($rowspan[$dayLoop] > 0) + { + $filled = TRUE; + $rowspan[$dayLoop] --; + } + + /* If the cell was not filled, fill it with an empty cell. */ + if(!$filled) + { + echo "\n"; + } + $filled = FALSE; + } + + // End of row + echo " |
There are no possible schedules. Please try again.
'; + } + + /* edit button */ + if ($id = $this->id_get()) + echo ''; + + echo "There were a total of " . $this->possiblePermutations . " possible permutations. Only " . $this->nPermutations . " permutations had no class conflicts.
"; + + $outputPage->foot(); + } + + //-------------------------------------------------- + // Changes the title of the page. + //-------------------------------------------------- + function changeTitle($t) + { + $this->title = $t; + } + + //-------------------------------------------------- + // Make the time "pretty" + //-------------------------------------------------- + function prettyTime($t){ + if($t > 1259) + { + $t = ($t-1200); + return substr($t, 0, strlen($t)-2) . ":" . substr($t, strlen($t)-2, strlen($t)) . " PM"; + } else { + return substr($t, 0, strlen($t)-2) . ":" . substr($t, strlen($t)-2, strlen($t)) . " AM"; + } + } + + /** + * \brief + * fetch the number of classes + */ + function nclasses_get() + { + return count($this->courses); + } + + /** + * \brief + * fetch a specified class by its key + */ + function class_get($class_key) + { + return $this->courses[$class_key]; + } + + /** + * \brief + * Set my global ID. + * + * Only to be called by schedule_store_store(). + */ + function id_set($id) + { + $this->id = $id; + } + + /* + * \brief + * Get my global ID. + */ + function id_get() + { + return $this->id; + } + + /** + * \brief + * Write out a relative URL for a particular schedule. + * + * Takes into account the $clean_urls setting. + * + * \param $id + * The ID of the schedule to link to. Defaults to the current schedule object. + * \param $page + * The page of the schedule to link to. Defaults to 0. + * \return + * A string, the URL used to access this schedule. Remember that + * if this string is inserted into an XHTML document, + * htmlentities() must be called on it. + */ + function url($id = NULL, $page = 0) + { + global $clean_urls; + + $url = ''; + if (!$clean_urls) + $url .= 'process.php?s='; + + if (!$id) + $id = $this->id; + $url .= (int)$id; + if ($clean_urls) + $url .= '?'; + else + $url .= '&'; + + if ($page) + $url .= 'page=' . (int)$page . '&'; + + return $url; + } + + /** + * \brief + * A magic function which tries to upgrade old serialized sections + * to the new format. + */ + function __wakeup() + { + if ($this->nclasses == -1) + /* this Schedule doesn't need to be upgraded from Classes to Course */ + return; + + $this->courses = array(); + foreach ($this->classStorage as $classes) + { + $this->courses[] = $classes->to_course(); + } + $this->nclasses = -1; + } +}