weekdaze-0.0.0.1: src-lib/WeekDaze/Data/Group.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@]
* 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