{-
    Copyright 2015,2016 Markus Ongyerth, Stephan Guenther

    This file is part of Monky.

    Monky is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Monky 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 Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with Monky.  If not, see <http://www.gnu.org/licenses/>.
-}
{-# LANGUAGE OverloadedStrings #-}
{-|
Module      : Monky.Memory
Description : Allows to access information about they systems main memory
Maintainer  : ongy
Stability   : testing
Portability : Linux

-}
module Monky.Memory
  ( MemoryHandle
  , getMemoryAvailable
  , getMemoryHandle
  , getMemoryTotal
  , getMemoryUsed
  , getMemoryFree
  , getMemoryStats
  )
where

import Monky.Utility (fopen, readContent, File)
import Data.Maybe (fromMaybe, listToMaybe)

import Data.ByteString (ByteString)
import qualified Data.ByteString.Char8 as BS


-- |The memory handle used for all functions
data MemoryHandle = MemoryH File

path :: String
path = "/proc/meminfo"

getVal :: ByteString -> Int
getVal = fst . fromMaybe (error "Failed to read as int in memory module") .  BS.readInt . (!! 1) . BS.words


findLine :: ByteString -> [ByteString] -> Maybe ByteString
findLine x = listToMaybe . filter (x `BS.isPrefixOf`)

-- |Return the memory available to processes
getMemoryAvailable :: MemoryHandle -> IO Int
getMemoryAvailable (MemoryH f) = do
  contents <- readContent f
  return $getVal $fromMaybe "a 0" $findLine "MemAvailable" contents

-- |Get the total amount of memory in the system
getMemoryTotal :: MemoryHandle -> IO Int
getMemoryTotal (MemoryH f) = do
  contents <- readContent f
  return $getVal $fromMaybe "a 0" $findLine "MemTotal" contents


-- |Get the amount of memory rported as free by the kernel
getMemoryFree :: MemoryHandle -> IO Int
getMemoryFree (MemoryH f) = do
  contents <- readContent f
  return . getVal . fromMaybe "a 0" . findLine "MemFree" $contents

-- |Get the amount of memory used by the kernel and processes
getMemoryUsed :: MemoryHandle -> IO Int
getMemoryUsed h = do
  (_, _, _, used) <- getMemoryStats h
  return used

-- |Get memory statistics in one got (with only one read) (total, avail, free, used)
getMemoryStats :: MemoryHandle -> IO (Int, Int, Int, Int)
getMemoryStats (MemoryH f) = do
  contents <- readContent f
  let avail = getVal . fromMaybe "a 0" . findLine "MemAvailable" $ contents
      total = getVal . fromMaybe "a 0" . findLine "MemTotal" $ contents
      free = getVal . fromMaybe "a 0" . findLine "MemFree" $ contents
      used = (total - avail)
  return (total, avail, free, used)


-- |Get a memory handle
getMemoryHandle :: IO MemoryHandle
getMemoryHandle = do
  file <- fopen path
  return $MemoryH file