{-|
Module      : RoomsHandler
Description : Módulo contendo as operações básicas para manipulação de salas no sistema SIGES.
-}
module Handlers.RoomsHandler where

import Manager
import Handlers.DataHandler

instance Show Room where
    show :: Room -> String
show(Room String
codeRoom [Reservation]
_ [Resource]
resRoom Int
capRoom String
localRoom RoomCategory
catRoom) =   String
"Dados da sala:                   \n\
                                                                \Código: "String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
codeRoom String -> ShowS
forall a. [a] -> [a] -> [a]
++         String
"\n\
                                                                \Categoria: "String -> ShowS
forall a. [a] -> [a] -> [a]
++ RoomCategory -> String
forall a. Show a => a -> String
show RoomCategory
catRoom String -> ShowS
forall a. [a] -> [a] -> [a]
++  String
"\n\
                                                                \Capacidade: "String -> ShowS
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show Int
capRoom String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"\n\
                                                                \Localização: "String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
localRoom String -> ShowS
forall a. [a] -> [a] -> [a]
++   String
"\n\
                                                                \Recursos: "String -> ShowS
forall a. [a] -> [a] -> [a]
++ [Resource] -> String
forall a. Show a => a -> String
show [Resource]
resRoom

instance Show Reservation where
    show :: Reservation -> String
show(Reservation String
requester String
description LocalTime
startTime LocalTime
finishTime) = String
"Dados da reserva:                 \n\
                                                                   \Início: "String -> ShowS
forall a. [a] -> [a] -> [a]
++ LocalTime -> String
forall a. Show a => a -> String
show LocalTime
startTime String -> ShowS
forall a. [a] -> [a] -> [a]
++    String
"\n\
                                                                   \Fim: "String -> ShowS
forall a. [a] -> [a] -> [a]
++ LocalTime -> String
forall a. Show a => a -> String
show LocalTime
finishTime String -> ShowS
forall a. [a] -> [a] -> [a]
++      String
"\n\
                                                                   \Responsável: " String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
requester String -> ShowS
forall a. [a] -> [a] -> [a]
++   String
"\n\
                                                                   \Motivo: "String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
description

instance Ord Reservation where
    compare :: Reservation -> Reservation -> Ordering
compare Reservation
res1 Reservation
res2 = if Reservation -> LocalTime
startTime Reservation
res1 LocalTime -> LocalTime -> Bool
forall a. Ord a => a -> a -> Bool
<= Reservation -> LocalTime
startTime Reservation
res2 then Ordering
LT else Ordering
GT

instance Show Resource where
    show :: Resource -> String
show(Resource ResourceKind
kind Int
quantity) = String
" " String -> ShowS
forall a. [a] -> [a] -> [a]
++ ResourceKind -> String
forall a. Show a => a -> String
show ResourceKind
kind String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
": " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show Int
quantity

-- | Função que, dadas todas as informações de uma sala, a cria e a persiste no banco de dados, retornando o booleano que representa o sucesso da operação
createRoom :: String -> [Resource] -> RoomCategory -> Int -> String -> IO Bool
createRoom :: String -> [Resource] -> RoomCategory -> Int -> String -> IO Bool
createRoom String
code [Resource]
res RoomCategory
cat Int
cap String
loc = do
    let codeRoom :: String
codeRoom = (Char -> Char) -> ShowS
forall a b. (a -> b) -> [a] -> [b]
map Char -> Char
toUpper String
code
    let newRoom :: Room
newRoom = Room :: String
-> [Reservation]
-> [Resource]
-> Int
-> String
-> RoomCategory
-> Room
Room{code :: String
code=String
codeRoom, schedule :: [Reservation]
schedule=[], resources :: [Resource]
resources=[Resource]
res, capacity :: Int
capacity=Int
cap, localization :: String
localization=String
loc, category :: RoomCategory
category = RoomCategory
cat}
    Room -> IO Bool
saveRoom Room
newRoom

-- | Função auxiliar que, dada uma tupla com um Integer para o ano e um Int para mÊs, dia, hora e minuto, respectivamente, cria um LocalTime.
makeTime :: (Integer, Int, Int, Int, Int) -> LocalTime
makeTime :: (Integer, Int, Int, Int, Int) -> LocalTime
makeTime (Integer
a, Int
m, Int
d, Int
h, Int
min) = LocalTime
time
    where (Just TimeOfDay
clock) = Int -> Int -> Pico -> Maybe TimeOfDay
makeTimeOfDayValid Int
h Int
min Pico
00
          calendar :: Day
calendar = Integer -> Int -> Int -> Day
fromGregorian Integer
a Int
m Int
d
          time :: LocalTime
time = Day -> TimeOfDay -> LocalTime
LocalTime Day
calendar TimeOfDay
clock

-- | Esta função recebe uma sala e um horário, e verifica se esta sala estará livre neste horário, respondendo com um valor booleano.
isFree :: Room -> LocalTime -> Bool
isFree :: Room -> LocalTime -> Bool
isFree Room
room LocalTime
newTime = Bool -> Bool
not (Bool -> Bool) -> Bool -> Bool
forall a b. (a -> b) -> a -> b
$ (Reservation -> Bool) -> [Reservation] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (\Reservation
reservation -> (Reservation -> LocalTime
startTime Reservation
reservation LocalTime -> LocalTime -> Bool
forall a. Ord a => a -> a -> Bool
<= LocalTime
newTime) Bool -> Bool -> Bool
&& (Reservation -> LocalTime
finishTime Reservation
reservation LocalTime -> LocalTime -> Bool
forall a. Ord a => a -> a -> Bool
>= LocalTime
newTime)) (Room -> [Reservation]
schedule Room
room)

-- | Esta função criará uma reserva em uma das salas, a partir do código da mesma, do nome do responsável pela reserva, e das tuplas especificando data e horário de finalização do evento.
makeReservation :: String -> String -> String -> (Integer, Int, Int, Int, Int) -> (Integer, Int, Int, Int, Int) -> IO Bool
makeReservation :: String
-> String
-> String
-> (Integer, Int, Int, Int, Int)
-> (Integer, Int, Int, Int, Int)
-> IO Bool
makeReservation String
codeStr String
userName String
descriptionStr (Integer, Int, Int, Int, Int)
startTimeTuple (Integer, Int, Int, Int, Int)
finishTimeTuple = do
    let codeRoom :: String
codeRoom = (Char -> Char) -> ShowS
forall a b. (a -> b) -> [a] -> [b]
map Char -> Char
toUpper String
codeStr
        startTimeReservation :: LocalTime
startTimeReservation = (Integer, Int, Int, Int, Int) -> LocalTime
makeTime (Integer, Int, Int, Int, Int)
startTimeTuple
        finishTimeReservation :: LocalTime
finishTimeReservation = (Integer, Int, Int, Int, Int) -> LocalTime
makeTime (Integer, Int, Int, Int, Int)
finishTimeTuple
    (Just Room
room) <- String -> IO (Maybe Room)
getRoom String
codeRoom

    if Room -> LocalTime -> Bool
isFree Room
room LocalTime
startTimeReservation Bool -> Bool -> Bool
&& Room -> LocalTime -> Bool
isFree Room
room LocalTime
finishTimeReservation
        then do
            let newReservation :: Reservation
newReservation = Reservation :: String -> String -> LocalTime -> LocalTime -> Reservation
Reservation{requester :: String
requester=String
userName, description :: String
description=String
descriptionStr, startTime :: LocalTime
startTime=LocalTime
startTimeReservation, finishTime :: LocalTime
finishTime=LocalTime
finishTimeReservation}
                newSchedule :: [Reservation]
newSchedule = Reservation -> [Reservation] -> [Reservation]
forall a. Ord a => a -> [a] -> [a]
insert Reservation
newReservation (Room -> [Reservation]
schedule Room
room)
                newRoom :: Room
newRoom = Room :: String
-> [Reservation]
-> [Resource]
-> Int
-> String
-> RoomCategory
-> Room
Room{code :: String
code=Room -> String
code Room
room, schedule :: [Reservation]
schedule=[Reservation]
newSchedule, resources :: [Resource]
resources=Room -> [Resource]
resources Room
room, capacity :: Int
capacity=Room -> Int
capacity Room
room, localization :: String
localization=Room -> String
localization Room
room, category :: RoomCategory
category =Room -> RoomCategory
category Room
room}

            String -> Room -> IO Bool
updateRoom String
codeRoom Room
newRoom
            Bool -> IO Bool
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
True
        else
            Bool -> IO Bool
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
False

-- | Esta função deletará uma função identificada pelo código da sala e nome do responsável, e pela tupla do horário de início do evento.
deleteReservation :: String -> String -> (Integer, Int, Int, Int, Int) -> IO Bool
deleteReservation :: String -> String -> (Integer, Int, Int, Int, Int) -> IO Bool
deleteReservation String
codeStr String
userName (Integer, Int, Int, Int, Int)
startTimeTuple = do
    let codeRoom :: String
codeRoom = (Char -> Char) -> ShowS
forall a b. (a -> b) -> [a] -> [b]
map Char -> Char
toUpper String
codeStr
        timeReservation :: LocalTime
timeReservation = (Integer, Int, Int, Int, Int) -> LocalTime
makeTime (Integer, Int, Int, Int, Int)
startTimeTuple
    (Just Room
room) <- String -> IO (Maybe Room)
getRoom String
codeRoom

    if (Reservation -> Bool) -> [Reservation] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (\Reservation
reservation -> (Reservation -> LocalTime
startTime Reservation
reservation LocalTime -> LocalTime -> Bool
forall a. Eq a => a -> a -> Bool
== LocalTime
timeReservation) Bool -> Bool -> Bool
&& (Reservation -> String
requester Reservation
reservation String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== String
userName)) (Room -> [Reservation]
schedule Room
room)
        then do
            let newSchedule :: [Reservation]
newSchedule = (Reservation -> Bool) -> [Reservation] -> [Reservation]
forall a. (a -> Bool) -> [a] -> [a]
filter (\Reservation
reservation -> Reservation -> LocalTime
startTime Reservation
reservation LocalTime -> LocalTime -> Bool
forall a. Eq a => a -> a -> Bool
/= LocalTime
timeReservation) (Room -> [Reservation]
schedule Room
room)
                newRoom :: Room
newRoom = Room :: String
-> [Reservation]
-> [Resource]
-> Int
-> String
-> RoomCategory
-> Room
Room{code :: String
code=Room -> String
code Room
room, schedule :: [Reservation]
schedule=[Reservation]
newSchedule, resources :: [Resource]
resources=Room -> [Resource]
resources Room
room, capacity :: Int
capacity=Room -> Int
capacity Room
room, localization :: String
localization=Room -> String
localization Room
room, category :: RoomCategory
category=Room -> RoomCategory
category Room
room}

            String -> Room -> IO Bool
updateRoom String
codeRoom Room
newRoom
            Bool -> IO Bool
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
True

        else Bool -> IO Bool
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
False

-- | Dada uma sala, identificada pelo seu código, um horário, representado em forma de tupla e um nome de usuário, esta função retornará a reserva com os dados equivalentes.
findReservation :: String -> (Integer,Int,Int,Int,Int)-> String -> IO Reservation
findReservation :: String -> (Integer, Int, Int, Int, Int) -> String -> IO Reservation
findReservation String
codeRoom (Integer, Int, Int, Int, Int)
startTimeTuple String
userName = do
    (Just Room
room) <- String -> IO (Maybe Room)
getRoom String
codeRoom
    let reservations :: [Reservation]
reservations = Room -> [Reservation]
schedule Room
room
        matching :: [Reservation]
matching = (Reservation -> Bool) -> [Reservation] -> [Reservation]
forall a. (a -> Bool) -> [a] -> [a]
filter (\Reservation
reservation -> (Reservation -> LocalTime
startTime Reservation
reservation LocalTime -> LocalTime -> Bool
forall a. Eq a => a -> a -> Bool
== (Integer, Int, Int, Int, Int) -> LocalTime
makeTime (Integer, Int, Int, Int, Int)
startTimeTuple) Bool -> Bool -> Bool
&& (Reservation -> String
requester Reservation
reservation String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== String
userName)) [Reservation]
reservations
    Reservation -> IO Reservation
forall (m :: * -> *) a. Monad m => a -> m a
return (Reservation -> IO Reservation) -> Reservation -> IO Reservation
forall a b. (a -> b) -> a -> b
$ [Reservation] -> Reservation
forall a. [a] -> a
head [Reservation]
matching

-- | Dada uma sala, identificada pelo seu código, e um horário em forma de tupla, esta função retornará a reserva da sala cujo evento se inicie no horário dado.
findReservationEasy :: String -> (Integer,Int,Int,Int,Int) -> IO Reservation
findReservationEasy :: String -> (Integer, Int, Int, Int, Int) -> IO Reservation
findReservationEasy String
codeRoom (Integer, Int, Int, Int, Int)
startTimeTuple = do
    (Just Room
room) <- String -> IO (Maybe Room)
getRoom String
codeRoom
    let reservations :: [Reservation]
reservations = Room -> [Reservation]
schedule Room
room
        matching :: [Reservation]
matching = (Reservation -> Bool) -> [Reservation] -> [Reservation]
forall a. (a -> Bool) -> [a] -> [a]
filter (\Reservation
reservation -> (Reservation -> LocalTime
startTime Reservation
reservation LocalTime -> LocalTime -> Bool
forall a. Eq a => a -> a -> Bool
== (Integer, Int, Int, Int, Int) -> LocalTime
makeTime (Integer, Int, Int, Int, Int)
startTimeTuple)) [Reservation]
reservations
    Reservation -> IO Reservation
forall (m :: * -> *) a. Monad m => a -> m a
return (Reservation -> IO Reservation) -> Reservation -> IO Reservation
forall a b. (a -> b) -> a -> b
$ [Reservation] -> Reservation
forall a. [a] -> a
head [Reservation]
matching


-- | Esta função alterará o horário de uma reserva (identificada pelo código de sua sala, pelo seu responsável e horário de início). Caso não seja possível fazer a alteração, nada será feito. A função retornará um valor booleano indicando se foi possível fazer a operação.
editReservation :: String -> String -> (Integer, Int, Int, Int, Int) -> (Integer, Int, Int, Int, Int) -> (Integer, Int, Int, Int, Int) -> IO Bool
editReservation :: String
-> String
-> (Integer, Int, Int, Int, Int)
-> (Integer, Int, Int, Int, Int)
-> (Integer, Int, Int, Int, Int)
-> IO Bool
editReservation String
codeStr String
userName (Integer, Int, Int, Int, Int)
currentStartTimeTuple (Integer, Int, Int, Int, Int)
newStartTimeTuple (Integer, Int, Int, Int, Int)
newFinishTimeTuple = do
    let codeRoom :: String
codeRoom = (Char -> Char) -> ShowS
forall a b. (a -> b) -> [a] -> [b]
map Char -> Char
toUpper String
codeStr
    (Just Room
room) <- String -> IO (Maybe Room)
getRoom String
codeRoom
    let currentStartTime :: LocalTime
currentStartTime = (Integer, Int, Int, Int, Int) -> LocalTime
makeTime (Integer, Int, Int, Int, Int)
currentStartTimeTuple
        newStartTime :: LocalTime
newStartTime = (Integer, Int, Int, Int, Int) -> LocalTime
makeTime (Integer, Int, Int, Int, Int)
newStartTimeTuple
        newFinishTime :: LocalTime
newFinishTime = (Integer, Int, Int, Int, Int) -> LocalTime
makeTime (Integer, Int, Int, Int, Int)
newFinishTimeTuple
        reservationExists :: Bool
reservationExists = (Reservation -> Bool) -> [Reservation] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (\Reservation
reservation -> Reservation -> LocalTime
startTime Reservation
reservation LocalTime -> LocalTime -> Bool
forall a. Eq a => a -> a -> Bool
== LocalTime
currentStartTime Bool -> Bool -> Bool
&& Reservation -> String
requester Reservation
reservation String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== String
userName) (Room -> [Reservation]
schedule Room
room)
        newTimeIsFree :: Bool
newTimeIsFree = Room -> LocalTime -> Bool
isFree Room
room LocalTime
newStartTime Bool -> Bool -> Bool
&& Room -> LocalTime -> Bool
isFree Room
room LocalTime
newFinishTime

    if Bool
reservationExists Bool -> Bool -> Bool
&& Bool
newTimeIsFree
        then do
            let currentReservation :: Reservation
currentReservation = [Reservation] -> Reservation
forall a. [a] -> a
head ([Reservation] -> Reservation) -> [Reservation] -> Reservation
forall a b. (a -> b) -> a -> b
$ (Reservation -> Bool) -> [Reservation] -> [Reservation]
forall a. (a -> Bool) -> [a] -> [a]
filter (\Reservation
reservation -> Reservation -> LocalTime
startTime Reservation
reservation LocalTime -> LocalTime -> Bool
forall a. Eq a => a -> a -> Bool
== LocalTime
currentStartTime) (Room -> [Reservation]
schedule Room
room)
                newReservation :: Reservation
newReservation = Reservation :: String -> String -> LocalTime -> LocalTime -> Reservation
Reservation{requester :: String
requester = String
userName, description :: String
description = Reservation -> String
description Reservation
currentReservation, startTime :: LocalTime
startTime = LocalTime
newStartTime, finishTime :: LocalTime
finishTime = LocalTime
newFinishTime}
                newSchedule :: [Reservation]
newSchedule = Reservation -> [Reservation] -> [Reservation]
forall a. Ord a => a -> [a] -> [a]
insert Reservation
newReservation ((Reservation -> Bool) -> [Reservation] -> [Reservation]
forall a. (a -> Bool) -> [a] -> [a]
filter (\Reservation
reservation -> Reservation -> LocalTime
startTime Reservation
reservation LocalTime -> LocalTime -> Bool
forall a. Eq a => a -> a -> Bool
/= LocalTime
currentStartTime) (Room -> [Reservation]
schedule Room
room))
                newRoom :: Room
newRoom = Room :: String
-> [Reservation]
-> [Resource]
-> Int
-> String
-> RoomCategory
-> Room
Room{code :: String
code=Room -> String
code Room
room, schedule :: [Reservation]
schedule=[Reservation]
newSchedule, resources :: [Resource]
resources=Room -> [Resource]
resources Room
room, capacity :: Int
capacity=Room -> Int
capacity Room
room, localization :: String
localization=Room -> String
localization Room
room, category :: RoomCategory
category=Room -> RoomCategory
category Room
room}

            String -> Room -> IO Bool
updateRoom String
codeRoom Room
newRoom
            Bool -> IO Bool
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
True

        else do
            Bool -> IO Bool
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
False


-- | Dado um LocalTime para comparação, esta função irá retirar de uma determinada sala as reservas finalizadas antes deste horário.
cleanReservations :: LocalTime -> Room -> Room
cleanReservations :: LocalTime -> Room -> Room
cleanReservations LocalTime
timeNow Room
room = Room :: String
-> [Reservation]
-> [Resource]
-> Int
-> String
-> RoomCategory
-> Room
Room{code :: String
code=Room -> String
code Room
room, schedule :: [Reservation]
schedule=[Reservation]
newSchedule, resources :: [Resource]
resources=Room -> [Resource]
resources Room
room, capacity :: Int
capacity=Room -> Int
capacity Room
room, localization :: String
localization=Room -> String
localization Room
room, category :: RoomCategory
category=Room -> RoomCategory
category Room
room}
    where newSchedule :: [Reservation]
newSchedule = (Reservation -> Bool) -> [Reservation] -> [Reservation]
forall a. (a -> Bool) -> [a] -> [a]
filter (\Reservation
reservation -> Reservation -> LocalTime
finishTime Reservation
reservation LocalTime -> LocalTime -> Bool
forall a. Ord a => a -> a -> Bool
< LocalTime
timeNow) (Room -> [Reservation]
schedule Room
room)

-- | Esta função removerá de todas as salas as reservas cujo horário de final do evento já passou.
cleanAllReservations :: IO Bool
cleanAllReservations :: IO Bool
cleanAllReservations = do
    UTCTime
utcTimeNow <- IO UTCTime
getCurrentTime
    TimeZone
timeZone <- UTCTime -> IO TimeZone
getTimeZone UTCTime
utcTimeNow
    let timeNow :: LocalTime
timeNow = TimeZone -> UTCTime -> LocalTime
utcToLocalTime TimeZone
timeZone UTCTime
utcTimeNow
    (Room -> Room) -> IO Bool
updateAllRooms (LocalTime -> Room -> Room
cleanReservations LocalTime
timeNow)

-- | Dado um dia representado em uma tupla e um código de sala, esta função criará um relatório em texto com todas as reservas que esta sala tem para o dia especificado.
createReportForTheRoom :: (Integer, Int, Int) -> Room -> String
createReportForTheRoom :: (Integer, Int, Int) -> Room -> String
createReportForTheRoom (Integer
a, Int
m, Int
d) Room
room = String
result
    where calendar :: Day
calendar = Integer -> Int -> Int -> Day
fromGregorian Integer
a Int
m Int
d
          reservations :: [Reservation]
reservations = (Reservation -> Bool) -> [Reservation] -> [Reservation]
forall a. (a -> Bool) -> [a] -> [a]
filter (\Reservation
reservation -> LocalTime -> Day
localDay (Reservation -> LocalTime
startTime Reservation
reservation) Day -> Day -> Bool
forall a. Eq a => a -> a -> Bool
== Day
calendar) (Room -> [Reservation]
schedule Room
room)
          reservationsList :: [String]
reservationsList = (String
"Relatório de ocupação para a sala " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Room -> String
code Room
room String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" no dia: " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Day -> String
forall a. Show a => a -> String
show Day
calendar String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
":\n\n")String -> [String] -> [String]
forall a. a -> [a] -> [a]
: (Reservation -> String) -> [Reservation] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map Reservation -> String
forall a. Show a => a -> String
show [Reservation]
reservations
          result :: String
result = String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
intercalate String
"\n" [String]
reservationsList

-- | Dado um dia representado em uma tupla, esta função criará um relatório em texto para todas as reservas de todas as salas para o dia especificado.
createReportForTheDay :: (Integer, Int, Int) -> IO String
createReportForTheDay :: (Integer, Int, Int) -> IO String
createReportForTheDay (Integer, Int, Int)
calendarTuple = do
    [Room]
allRooms <- IO [Room]
fetchRooms
    let reportsList :: [String]
reportsList = (Room -> String) -> [Room] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map ((Integer, Int, Int) -> Room -> String
createReportForTheRoom (Integer, Int, Int)
calendarTuple) [Room]
allRooms
        result :: String
result = String
"Relatório de ocupação de salas:\n\n" String -> ShowS
forall a. [a] -> [a] -> [a]
++ String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
intercalate String
"\n\n===========\\===========\n\n" [String]
reportsList

    String -> IO String
forall (m :: * -> *) a. Monad m => a -> m a
return String
result

-- | Com uma categoria especificada, esta função verificará o sistema e retornará a lista contendo todas as salas desta categoria.
searchRoomsCategory :: RoomCategory -> IO [Room]
searchRoomsCategory :: RoomCategory -> IO [Room]
searchRoomsCategory RoomCategory
catRoom = do
    [Room]
allRooms <- IO [Room]
fetchRooms
    let filtered :: [Room]
filtered = (Room -> Bool) -> [Room] -> [Room]
forall a. (a -> Bool) -> [a] -> [a]
filter (\Room
room -> Room -> RoomCategory
category Room
room RoomCategory -> RoomCategory -> Bool
forall a. Eq a => a -> a -> Bool
== RoomCategory
catRoom) [Room]
allRooms
    [Room] -> IO [Room]
forall (m :: * -> *) a. Monad m => a -> m a
return [Room]
filtered


-- | Com uma capacidade especificada, esta função verificará o sistema e retornará a lista contendo todas as salas com esta capacidade ou mais.
searchRoomsCapacity :: Int -> IO [Room]
searchRoomsCapacity :: Int -> IO [Room]
searchRoomsCapacity Int
capRoom = do
    [Room]
allRooms <- IO [Room]
fetchRooms
    let filtered :: [Room]
filtered = (Room -> Bool) -> [Room] -> [Room]
forall a. (a -> Bool) -> [a] -> [a]
filter (\Room
room -> Room -> Int
capacity Room
room Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
capRoom) [Room]
allRooms
    [Room] -> IO [Room]
forall (m :: * -> *) a. Monad m => a -> m a
return [Room]
filtered

-- | Com um horário de início e fim especificado em forma de tupla, esta função verificará o sistema e retornará a lista contendo todas as salas que estejam livres neste horário.
searchRoomsTime :: (Integer, Int, Int, Int, Int) -> (Integer, Int, Int, Int, Int) -> IO [Room]
searchRoomsTime :: (Integer, Int, Int, Int, Int)
-> (Integer, Int, Int, Int, Int) -> IO [Room]
searchRoomsTime (Integer, Int, Int, Int, Int)
startTimeTuple (Integer, Int, Int, Int, Int)
finishTimeTuple = do
    [Room]
allRooms <- IO [Room]
fetchRooms
    let startTime :: LocalTime
startTime = (Integer, Int, Int, Int, Int) -> LocalTime
makeTime (Integer, Int, Int, Int, Int)
startTimeTuple
        finishTime :: LocalTime
finishTime = (Integer, Int, Int, Int, Int) -> LocalTime
makeTime (Integer, Int, Int, Int, Int)
finishTimeTuple
        filtered :: [Room]
filtered = (Room -> Bool) -> [Room] -> [Room]
forall a. (a -> Bool) -> [a] -> [a]
filter (\Room
room -> Room -> LocalTime -> Bool
isFree Room
room LocalTime
startTime Bool -> Bool -> Bool
&& Room -> LocalTime -> Bool
isFree Room
room LocalTime
finishTime) [Room]
allRooms
    [Room] -> IO [Room]
forall (m :: * -> *) a. Monad m => a -> m a
return [Room]
filtered

-- | Esta função recebe uma sala e um Resource e verifica se esta sala tem o recurso e se o tem na quantidade especificada ou superior, retornando a resposta em forma de valor booleano.
resourceIsEnough :: Room -> Resource -> Bool
resourceIsEnough :: Room -> Resource -> Bool
resourceIsEnough Room
room Resource
r | (Resource -> Bool) -> [Resource] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (\Resource
roomResource -> (Resource -> ResourceKind
resourceKind Resource
roomResource ResourceKind -> ResourceKind -> Bool
forall a. Eq a => a -> a -> Bool
== Resource -> ResourceKind
resourceKind Resource
r) Bool -> Bool -> Bool
&& (Resource -> Int
resourceQuantity Resource
roomResource Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Resource -> Int
resourceQuantity Resource
r)) (Room -> [Resource]
resources Room
room) = Bool
True
                        | Bool
otherwise = Bool
False

-- | Esta função verificará se uma sala contém todos os recursos em uma lista, e se os tem na quantidade especificada ou superior.
containsResources :: [Resource] -> Room -> Bool
containsResources :: [Resource] -> Room -> Bool
containsResources [] Room
_ = Bool
True
containsResources [Resource]
rs Room
room = (Resource -> Bool) -> [Resource] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (Room -> Resource -> Bool
resourceIsEnough Room
room) [Resource]
rs

-- | Com uma lista de recursos especificada, esta função verificará o sistema e retornará a lista contendo todas as salas que supram esta demanda.
searchRoomsResources :: [Resource] -> IO [Room]
searchRoomsResources :: [Resource] -> IO [Room]
searchRoomsResources [Resource]
resourcesNeeded = do
    [Room]
allRooms <- IO [Room]
fetchRooms
    let filtered :: [Room]
filtered = (Room -> Bool) -> [Room] -> [Room]
forall a. (a -> Bool) -> [a] -> [a]
filter ([Resource] -> Room -> Bool
containsResources [Resource]
resourcesNeeded) [Room]
allRooms
    [Room] -> IO [Room]
forall (m :: * -> *) a. Monad m => a -> m a
return [Room]
filtered

-- | Dado um nome de usuário e uma sala, esta função verifica se a sala foi reservada por este usuário para algum horário e retorna a resposta em forma de valor booleano.
wasReservedBy :: String -> Room -> Bool
wasReservedBy :: String -> Room -> Bool
wasReservedBy String
requesterName Room
room = Bool
result
    where result :: Bool
result = (Reservation -> Bool) -> [Reservation] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (\Reservation
reservation -> String
requesterName String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== Reservation -> String
requester Reservation
reservation) (Room -> [Reservation]
schedule Room
room)

-- | Com um nome de usuário especificado, esta função verificará o sistema e retornará a lista contendo todas as salas que foram reservadas para algum horário por aquele usuário.
searchRoomsRequester :: String -> IO [Room]
searchRoomsRequester :: String -> IO [Room]
searchRoomsRequester String
requesterName = do
    [Room]
allRooms <- IO [Room]
fetchRooms
    let filtered :: [Room]
filtered = (Room -> Bool) -> [Room] -> [Room]
forall a. (a -> Bool) -> [a] -> [a]
filter (String -> Room -> Bool
wasReservedBy String
requesterName) [Room]
allRooms
    [Room] -> IO [Room]
forall (m :: * -> *) a. Monad m => a -> m a
return [Room]
filtered

-- | Esta função produzirá um texto contendo a lista de todas as categorias de sala suportadas pelo sistema.
printCategories :: IO ()
printCategories :: IO ()
printCategories = do
    String -> IO ()
putStrLn String
"Qual categoria você deseja escolher?\n\
             \[L]aboratório\n\
             \[A]uditório\n\
             \[S]ala de aula\n\
             \[E]scritório\n\
             \[D]epósito"

-- | Esta função produzirá um texto listando todos os recursos oferecidos pelas salas do sistema.
printResources :: IO ()
printResources :: IO ()
printResources = do
    String -> IO ()
putStrLn String
"Qual recurso você deseja escolher?\n\
             \[P]rojetor\n\
             \[M]icroscópio\n\
             \[B]irô\n\
             \[C]omputador\n\
             \[Q]uadro\n\
             \[A]r condicionado"