-- -*- coding: utf-8; mode: haskell; -*-

-- File: library/Language/Ninja/Mock/ReadFile.hs
--
-- License:
--     Copyright 2017 Awake Security
--
--     Licensed under the Apache License, Version 2.0 (the "License");
--     you may not use this file except in compliance with the License.
--     You may obtain a copy of the License at
--
--       http://www.apache.org/licenses/LICENSE-2.0
--
--     Unless required by applicable law or agreed to in writing, software
--     distributed under the License is distributed on an "AS IS" BASIS,
--     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
--     See the License for the specific language governing permissions and
--     limitations under the License.

{-# LANGUAGE FlexibleContexts     #-}
{-# LANGUAGE FlexibleInstances    #-}
{-# LANGUAGE UndecidableInstances #-}

-- |
--   Module      : Language.Ninja.Mock.ReadFile
--   Copyright   : Copyright 2017 Awake Security
--   License     : Apache-2.0
--   Maintainer  : opensource@awakesecurity.com
--   Stability   : experimental
--
--   A typeclass exposing an interface that allows reading a file from a
--   filesystem (virtual or otherwise).
--
--   @since 0.1.0
module Language.Ninja.Mock.ReadFile
  ( MonadReadFile (..)
  ) where

import           Prelude                   (IO, Monad)

import           Control.Monad.Trans.Class (MonadTrans (lift))

import qualified Control.Lens              as Lens

import           Data.Text                 (Text)
import qualified Data.Text.IO              as Text

import           Language.Ninja.Misc.Path  (Path, pathString)

import           Flow                      ((.>))

--------------------------------------------------------------------------------

-- Remember: we have imported Prelude hiding 'readFile'.

-- | This typeclass allows you to write code that reads files from the
--   filesystem and then later run that code purely against a virtual filesystem
--   of some description.
--
--   @since 0.1.0
class (Monad m) => MonadReadFile m where
  {-# MINIMAL readFile #-}

  -- | Read the file located at the given path and decode it into 'Text'.
  --
  --   TODO: some notion of error handling should be encoded into the type
  --
  --   @since 0.1.0
  readFile :: Path -> m Text

-- | The obvious instance for 'IO'.
--
--   @since 0.1.0
instance MonadReadFile IO where
  readFile = Lens.view pathString .> Text.readFile

-- | A placeholder (undecidable) instance that allows this constraint to
--   propagate through monad transformers without needing to 'lift' manually.
--
--   @since 0.1.0
instance ( MonadTrans t, Monad (t m), MonadReadFile m
         ) => MonadReadFile (t m) where
  readFile = readFile .> lift

--------------------------------------------------------------------------------