{- |
Module:      PFile.Profile.LinkHandling
Copyright:   (c) 2024 Illia Shkroba
License:     BSD3
Maintainer:  Illia Shkroba <is@pjwstk.edu.pl>
Stability:   unstable
Portability: non-portable (Non-Unix systems are not supported)

Types and functions for handling links.
-}

{-# LANGUAGE FlexibleContexts  #-}
{-# LANGUAGE LambdaCase        #-}
{-# LANGUAGE OverloadedStrings #-}

module PFile.Profile.LinkHandling
  ( handle
  , showError
  , Error (..)
  , showStrategy
  , Strategy (..)
  ) where

import           PFile.Error (modifyError)
import           PFile.Path
  ( copyDirectory
  , copyFile
  , copyLink
  , createDirectory
  , createEmptyFile
  , doesDirectoryExist
  )
import qualified PFile.Path  as Path
import           Protolude   hiding (handle)

-- | Handle links relocation with 'Strategy':
--
-- * 'CopyFromOrigin' - copy source link's target to destination.
-- * 'CreateEmpty' - create an empty directory at destination when source
-- link's target is a directory or create an empty file at destination when
-- source link's target is a file.
-- * 'CopyLink' - copy source link to destination.
--
-- @since 0.1.0.0
handle ::
     (MonadError Error m, MonadIO m)
  => Strategy
  -> Path.Absolute
  -> Path.Absolute
  -> m ()
handle :: forall (m :: * -> *).
(MonadError Error m, MonadIO m) =>
Strategy -> Absolute -> Absolute -> m ()
handle Strategy
strategy Absolute
src Absolute
dest =
  case Strategy
strategy of
    Strategy
CopyFromOrigin ->
      m Bool -> m () -> m () -> m ()
forall (m :: * -> *) a. Monad m => m Bool -> m a -> m a -> m a
ifM (Absolute -> m Bool
forall (m :: * -> *). MonadIO m => Absolute -> m Bool
doesDirectoryExist Absolute
src)
        (Absolute -> Absolute -> ExceptT CopyError m ()
forall (m :: * -> *).
(MonadError CopyError m, MonadIO m) =>
Absolute -> Absolute -> m ()
copyDirectory Absolute
src Absolute
dest ExceptT CopyError m () -> (ExceptT CopyError m () -> m ()) -> m ()
forall a b. a -> (a -> b) -> b
& (CopyError -> Error) -> ExceptT CopyError m () -> m ()
forall e2 (m :: * -> *) e1 a.
MonadError e2 m =>
(e1 -> e2) -> ExceptT e1 m a -> m a
modifyError CopyError -> Error
CopyDirectoryFromOriginError)
        (Absolute -> Absolute -> ExceptT CopyFileError m ()
forall (m :: * -> *).
(MonadError CopyFileError m, MonadIO m) =>
Absolute -> Absolute -> m ()
copyFile Absolute
src Absolute
dest ExceptT CopyFileError m ()
-> (ExceptT CopyFileError m () -> m ()) -> m ()
forall a b. a -> (a -> b) -> b
& (CopyFileError -> Error) -> ExceptT CopyFileError m () -> m ()
forall e2 (m :: * -> *) e1 a.
MonadError e2 m =>
(e1 -> e2) -> ExceptT e1 m a -> m a
modifyError CopyFileError -> Error
CopyFileFromOriginError)
    Strategy
CreateEmpty ->
      m Bool -> m () -> m () -> m ()
forall (m :: * -> *) a. Monad m => m Bool -> m a -> m a -> m a
ifM (Absolute -> m Bool
forall (m :: * -> *). MonadIO m => Absolute -> m Bool
doesDirectoryExist Absolute
src)
        (Absolute -> ExceptT CreateDirectoryError m ()
forall (m :: * -> *).
(MonadError CreateDirectoryError m, MonadIO m) =>
Absolute -> m ()
createDirectory Absolute
dest ExceptT CreateDirectoryError m ()
-> (ExceptT CreateDirectoryError m () -> m ()) -> m ()
forall a b. a -> (a -> b) -> b
& (CreateDirectoryError -> Error)
-> ExceptT CreateDirectoryError m () -> m ()
forall e2 (m :: * -> *) e1 a.
MonadError e2 m =>
(e1 -> e2) -> ExceptT e1 m a -> m a
modifyError CreateDirectoryError -> Error
CreateEmptyDirectoryError)
        (Absolute -> ExceptT WriteFileError m ()
forall (m :: * -> *).
(MonadError WriteFileError m, MonadIO m) =>
Absolute -> m ()
createEmptyFile Absolute
dest ExceptT WriteFileError m ()
-> (ExceptT WriteFileError m () -> m ()) -> m ()
forall a b. a -> (a -> b) -> b
& (WriteFileError -> Error) -> ExceptT WriteFileError m () -> m ()
forall e2 (m :: * -> *) e1 a.
MonadError e2 m =>
(e1 -> e2) -> ExceptT e1 m a -> m a
modifyError WriteFileError -> Error
CreateEmptyFileError)
    Strategy
CopyLink -> Absolute -> Absolute -> ExceptT CopyLinkError m ()
forall (m :: * -> *).
(MonadError CopyLinkError m, MonadIO m) =>
Absolute -> Absolute -> m ()
copyLink Absolute
src Absolute
dest ExceptT CopyLinkError m ()
-> (ExceptT CopyLinkError m () -> m ()) -> m ()
forall a b. a -> (a -> b) -> b
& (CopyLinkError -> Error) -> ExceptT CopyLinkError m () -> m ()
forall e2 (m :: * -> *) e1 a.
MonadError e2 m =>
(e1 -> e2) -> ExceptT e1 m a -> m a
modifyError CopyLinkError -> Error
CopyLinkError

showError :: Error -> Text
showError :: Error -> Text
showError = \case
  CopyDirectoryFromOriginError CopyError
cause -> CopyError -> Text
Path.showCopyError CopyError
cause
  CopyFileFromOriginError CopyFileError
cause      -> CopyFileError -> Text
Path.showCopyFileError CopyFileError
cause
  CreateEmptyDirectoryError CreateDirectoryError
cause    -> CreateDirectoryError -> Text
Path.showCreateDirectoryError CreateDirectoryError
cause
  CreateEmptyFileError WriteFileError
cause         -> WriteFileError -> Text
Path.showWriteFileError WriteFileError
cause
  CopyLinkError CopyLinkError
cause                -> CopyLinkError -> Text
Path.showCopyLinkError CopyLinkError
cause

-- | Error thrown by 'handle'.
--
-- @since 0.1.0.0
data Error
  = CopyDirectoryFromOriginError !Path.CopyError
  -- ^ Error was encountered during 'PFile.Path.copyDirectory'.
  | CopyFileFromOriginError !Path.CopyFileError
  -- ^ Error was encountered during 'PFile.Path.copyFile'.
  | CreateEmptyDirectoryError !Path.CreateDirectoryError
  -- ^ Error was encountered during 'PFile.Path.createDirectory'.
  | CreateEmptyFileError !Path.WriteFileError
  -- ^ Error was encountered during 'PFile.Path.createEmptyFile'.
  | CopyLinkError !Path.CopyLinkError
  -- ^ Error was encountered during 'PFile.Path.copyLink'.

showStrategy :: Strategy -> Text
showStrategy :: Strategy -> Text
showStrategy = \case
  Strategy
CopyFromOrigin -> Text
"copy from origin"
  Strategy
CreateEmpty    -> Text
"create empty"
  Strategy
CopyLink       -> Text
"copy link"

-- | Link handling strategy for directory/file links to be used by 'handle'.
--
-- @since 0.1.0.0
data Strategy
  = CopyFromOrigin
  -- ^ Copy source link's target to destination.
  | CreateEmpty
  -- ^ Create an empty directory at destination when source link's target is
  -- a directory or create an empty file at destination when source link's
  -- target is a file.
  | CopyLink
  -- ^ Copy source link to destination.