weekdaze-0.0.0.1: src-exe/WeekDaze/Dynamic/HumanViewTimetable.hs
{-
Copyright (C) 2013-2015 Dr. Alistair Ward
This file is part of WeekDaze.
WeekDaze is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
WeekDaze is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with WeekDaze. If not, see <http://www.gnu.org/licenses/>.
-}
{- |
[@AUTHOR@] Dr. Alistair Ward
[@DESCRIPTION@]
Encapsulates the /timetable/ as seen from both /human-resource/ views;
i.e. from the /student-body/'s point-of-view & from the /teacher/'s.
-}
module WeekDaze.Dynamic.HumanViewTimetable(
-- * Types
-- ** Data-types
TimetablePair(
-- MkTimetablePair,
getStudentViewTimetable,
getTeacherViewTimetable
),
-- * Functions
-- ** Constructor
mkTimetablePair,
-- ** Mutators
book,
bookAtomically
) where
import Control.Arrow((&&&))
import qualified Data.Array.IArray
import qualified Data.Foldable
import qualified WeekDaze.Dynamic.TeacherViewTimetableUtilities as Dynamic.TeacherViewTimetableUtilities
import qualified WeekDaze.ExecutionConfiguration.ExecutionOptions as ExecutionConfiguration.ExecutionOptions
import qualified WeekDaze.Model.Timetable as Model.Timetable
import qualified WeekDaze.ProblemConfiguration.ProblemAnalysis as ProblemConfiguration.ProblemAnalysis
import qualified WeekDaze.StudentView.Timetable as StudentView.Timetable
import qualified WeekDaze.TeacherView.Timetable as TeacherView.Timetable
-- | Couples the two /human-resource/ views of a /timetable/, to facilitate synchronised changes.
data TimetablePair timeslotId locationId teacherId level = MkTimetablePair {
getStudentViewTimetable :: StudentView.Timetable.Timetable timeslotId locationId teacherId level, -- ^ The /timetable/ as seen from the /student-body/'s point-of-view.
getTeacherViewTimetable :: TeacherView.Timetable.Timetable teacherId timeslotId locationId level -- ^ The /timetable/ as seen from the /teacher/'s point-of-view.
}
-- | Constructor.
mkTimetablePair :: (
Data.Array.IArray.Ix timeslotId,
Enum timeslotId,
Eq level,
Eq locationId,
Ord teacherId,
Show level,
Show locationId,
Show teacherId,
Show timeslotId
)
=> ExecutionConfiguration.ExecutionOptions.ExecutionOptions criterionWeight fecundityDecayRatio populationDiversityRatio
-> ProblemConfiguration.ProblemAnalysis.ProblemAnalysis level locationId synchronisationId teacherId timeslotId
-> StudentView.Timetable.Timetable timeslotId locationId teacherId level
-> TimetablePair timeslotId locationId teacherId level
mkTimetablePair executionOptions problemAnalysis = uncurry ($) . (MkTimetablePair &&& Dynamic.TeacherViewTimetableUtilities.fromStudentViewTimetable executionOptions problemAnalysis)
{- |
* Book a /student-view lesson/ in both human views of the /timetable/.
* CAVEAT: doesn't check whether there's already a /lesson/ at the specified /coordinates/, which it may overwrite.
-}
book :: (
Data.Array.IArray.Ix timeslotId,
Eq level,
Eq locationId,
Ord teacherId,
Show level,
Show locationId,
Show teacherId,
Show timeslotId
)
=> ExecutionConfiguration.ExecutionOptions.PermitTemporaryStudentBodyMerger
-> StudentView.Timetable.Booking timeslotId locationId teacherId level -- ^ The booked from the /student/'s point-of-view.
-> TimetablePair timeslotId locationId teacherId level
-> TimetablePair timeslotId locationId teacherId level
book permitTemporaryStudentBodyMerger studentViewBooking = uncurry MkTimetablePair . (
Model.Timetable.defineTimeslot (Model.Timetable.toGeneralisedBooking studentViewBooking) . getStudentViewTimetable &&& TeacherView.Timetable.bookStudentViewLesson permitTemporaryStudentBodyMerger studentViewBooking . getTeacherViewTimetable
)
{- |
* Sequentially make the specified /booking/s, in the specified order, until either they're exhausted or the supplied predicate fails.
* Returns either the /TimetablePair/ including all the required /booking/s, or 'Nothing' on failure.
* CAVEAT: doesn't perform any native checks,
so it up to the caller to check whether the required bookings have already been made;
or whether to overwrite existing /booking/s.
-}
bookAtomically :: (
Data.Array.IArray.Ix timeslotId,
Data.Foldable.Foldable foldable,
Eq level,
Eq locationId,
Ord teacherId,
Show level,
Show locationId,
Show teacherId,
Show timeslotId
)
=> ExecutionConfiguration.ExecutionOptions.PermitTemporaryStudentBodyMerger
-> (
TimetablePair timeslotId locationId teacherId level
-> StudentView.Timetable.Booking timeslotId locationId teacherId level
-> Bool
) -- ^ Predicate based on a /TimetablePair/ & /booking/.
-> TimetablePair timeslotId locationId teacherId level -- ^ The initial /timetable/ on which to operate, as seen from the perspective of both /student/s & /teacher/s.
-> foldable (StudentView.Timetable.Booking timeslotId locationId teacherId level) -- ^ The ordered bookings to be placed.
-> Maybe (TimetablePair timeslotId locationId teacherId level) -- ^ Returns a /timetable-pair/ iff the /booking/s were completed.
bookAtomically permitTemporaryStudentBodyMerger predicate timetablePair = Data.Foldable.foldl' (
\maybeTimetablePair studentViewBooking -> maybeTimetablePair >>= \timetablePair' -> if predicate timetablePair' studentViewBooking
then Just $ book permitTemporaryStudentBodyMerger studentViewBooking timetablePair'
else Nothing
) (Just timetablePair)