{- 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 . -} {- | [@AUTHOR@] Dr. Alistair Ward [@DESCRIPTION@] * Describes groups of /student/s or /teacher/s. * Any number of different /group/s can exist. * /Student/s & /teacher/s can belong to any number of /group/s, & any /group/ can include both /student/s & /teacher/s. * This concept exists because of the probable requirement to book staff-meetings interleaved with the booking of normal classes; the requirement for /student/-groups isn't so clear, though perhaps Muslim student may need to pray at certain times within the normal working day. * Practice for a drama or choir, lunch or morning-assembly, might be other examples of /group-meeting/s, because in contrast to a normal /lesson/, more than one /teacher/ might be required to attend. -} module WeekDaze.Data.Group( -- * Types -- ** Type-synonyms Id, Membership, -- ** Data-types Profile( -- MkProfile, getMeetingTimes, getMaybeLocationId, getMandatesAttendance ), -- * Constants -- tag, groupIdTag, memberTag, mandatesAttendanceTag, meetingTimesTag, -- defaultMeetingTimes, defaultMandatesAttendance, -- * Functions countNTimeslotsPerWeek, -- ** Constructor mkProfile, -- ** Predicates -- hasLocation ) where import qualified Control.DeepSeq import qualified Data.Maybe import qualified Data.Set import qualified Text.XML.HXT.Arrow.Pickle as HXT import qualified Text.XML.HXT.DOM.Util import qualified ToolShed.SelfValidate import qualified WeekDaze.Size as Size import qualified WeekDaze.Temporal.Time as Temporal.Time import WeekDaze.Enhanced.EnhancedBool() -- | Used to qualify XML. tag :: String tag = "groupProfile" -- | Used to qualify CSS, SQL & XML. groupIdTag :: String groupIdTag = "groupId" -- | Used to qualify XML. memberTag :: String memberTag = "member" -- | Used to qualify SQL & XML. mandatesAttendanceTag :: String mandatesAttendanceTag = "mandatesAttendance" -- | Used to qualify XML. meetingTimesTag :: String meetingTimesTag = "meetingTimes" -- | The default value for 'getMeetingTimes'. defaultMeetingTimes :: Temporal.Time.TimeSet timeslotId defaultMeetingTimes = Data.Set.empty -- | The default value for 'getMandatesAttendance'. defaultMandatesAttendance :: Bool defaultMandatesAttendance = False -- | Names a /group/ to which /human-resource/ may belong. type Id = String -- | Aggregates the attributes of a /group/. data Profile timeslotId locationId = MkProfile { getMeetingTimes :: Temporal.Time.TimeSet timeslotId, -- ^ The list of meeting-times required of members of this group. getMaybeLocationId :: Maybe locationId, -- ^ The optional (it might be a teleconference, or there might currently be no meeting-times) /location/ at which all meetings will be held. getMandatesAttendance :: Bool -- ^ Whether each group-member is required to attend all meetings. } deriving (Eq, Read, Show) instance ToolShed.SelfValidate.SelfValidator (Profile timeslotId locationId) where getErrors _ = [] instance ( HXT.XmlPickler locationId, HXT.XmlPickler timeslotId, Ord timeslotId ) => HXT.XmlPickler (Profile timeslotId locationId) where xpickle = HXT.xpElem tag . HXT.xpWrap ( Text.XML.HXT.DOM.Util.uncurry3 mkProfile, -- Construct from a Triple. \MkProfile { getMeetingTimes = meetingTimes, getMaybeLocationId = maybeLocationId, getMandatesAttendance = mandatesAttendance } -> ( meetingTimes, maybeLocationId, mandatesAttendance ) -- Deconstruct to a Triple. ) $ HXT.xpTriple ( HXT.xpDefault defaultMeetingTimes . HXT.xpElem meetingTimesTag . HXT.xpWrap ( Data.Set.fromList, -- Construct from a List. Data.Set.toList -- Deconstruct into a List. ) $ HXT.xpList1 {-the default is null-} HXT.xpickle ) ( HXT.xpOption HXT.xpickle -- maybeLocationId. ) ( defaultMandatesAttendance `HXT.xpDefault` HXT.xpAttr mandatesAttendanceTag HXT.xpickle {-Bool-} ) instance ( Control.DeepSeq.NFData locationId, Control.DeepSeq.NFData timeslotId ) => Control.DeepSeq.NFData (Profile timeslotId locationId) where rnf (MkProfile x0 x1 x2) = Control.DeepSeq.rnf (x0, x1, x2) -- | Smart constructor. mkProfile :: Temporal.Time.TimeSet timeslotId -> Maybe locationId -> Bool -> Profile timeslotId locationId mkProfile meetingTimes locationId mandatesAttendance | ToolShed.SelfValidate.isValid profile = profile | otherwise = error $ "WeekDaze.Data.Group.mkProfile:\t" ++ ToolShed.SelfValidate.getFirstError profile ++ "." where profile = MkProfile meetingTimes locationId mandatesAttendance {- | * Counts the number of /time-slot/s per week required for /meeting/s of this /group/. * CAVEAT: this total is independent of the individual member, but if attendance isn't mandated, it should be reduced according to individual availability. -} countNTimeslotsPerWeek :: Profile timeslotId locationId -> Size.NTimeslots countNTimeslotsPerWeek = Data.Set.size . getMeetingTimes -- | Whether the /meeting/s of the specified /group/ have a designated /location/. hasLocation :: Profile timeslotId locationId -> Bool hasLocation = Data.Maybe.isJust . getMaybeLocationId -- | The /group/s to which a /human-resource/ belongs. type Membership = Data.Set.Set Id