module System.Path.Internal.Part where

import qualified Control.Monad.Trans.State as MS
import Control.Applicative ((<$>))
import Control.DeepSeq (NFData(rnf))

import Data.Tagged (Tagged(Tagged))
import Data.Ord.HT (comparing)
import Data.Eq.HT (equating)

import Test.QuickCheck (Gen)


newtype Abs = Abs GenComponent
data Rel = Rel
data AbsRel = AbsO GenComponent | RelO

absPC :: String -> Abs
absPC :: String -> Abs
absPC = GenComponent -> Abs
Abs forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall os. String -> PathComponent os
PathComponent

emptyPC :: PathComponent os
emptyPC :: forall os. PathComponent os
emptyPC = forall os. String -> PathComponent os
PathComponent String
""

newtype File = File GenComponent
data Dir = Dir
data FileDir = FileDir


instance NFData Abs where
    rnf :: Abs -> ()
rnf (Abs GenComponent
drive) = forall a. NFData a => a -> ()
rnf GenComponent
drive

instance NFData Rel where
    rnf :: Rel -> ()
rnf Rel
Rel = ()

instance NFData File where
    rnf :: File -> ()
rnf (File GenComponent
pc) = forall a. NFData a => a -> ()
rnf GenComponent
pc

instance NFData Dir where
    rnf :: Dir -> ()
rnf Dir
Dir = ()

instance NFData FileDir where
    rnf :: FileDir -> ()
rnf FileDir
FileDir = ()


data Generic = Generic


{- |
We cannot have a PathComponent without phantom types plus a Tagged wrapper,
because we need specialised Eq and Ord instances.
-}
type GenComponent = PathComponent Generic

newtype PathComponent os = PathComponent String

instance NFData (PathComponent os) where
    rnf :: PathComponent os -> ()
rnf (PathComponent String
pc) = forall a. NFData a => a -> ()
rnf String
pc

instance (System os) => Eq (PathComponent os) where
    == :: PathComponent os -> PathComponent os -> Bool
(==)  =  forall b a. Eq b => (a -> b) -> a -> a -> Bool
equating (forall os.
Tagged os (String -> String) -> PathComponent os -> String
applyComp forall os. System os => Tagged os (String -> String)
canonicalize)

instance (System os) => Ord (PathComponent os) where
    compare :: PathComponent os -> PathComponent os -> Ordering
compare  =  forall b a. Ord b => (a -> b) -> a -> a -> Ordering
comparing (forall os.
Tagged os (String -> String) -> PathComponent os -> String
applyComp forall os. System os => Tagged os (String -> String)
canonicalize)

applyComp :: Tagged os (String -> String) -> PathComponent os -> String
applyComp :: forall os.
Tagged os (String -> String) -> PathComponent os -> String
applyComp (Tagged String -> String
canon) (PathComponent String
pc) = String -> String
canon String
pc

retagPC :: GenComponent -> PathComponent os
retagPC :: forall os. GenComponent -> PathComponent os
retagPC (PathComponent String
pc) = forall os. String -> PathComponent os
PathComponent String
pc

untagPC :: PathComponent os -> GenComponent
untagPC :: forall os. PathComponent os -> GenComponent
untagPC (PathComponent String
pc) = forall os. String -> PathComponent os
PathComponent String
pc


fileMap :: (String -> String) -> File -> File
fileMap :: (String -> String) -> File -> File
fileMap String -> String
f (File GenComponent
pc) = GenComponent -> File
File forall a b. (a -> b) -> a -> b
$ forall os.
(String -> String) -> PathComponent os -> PathComponent os
pcMap String -> String
f GenComponent
pc

pcMap :: (String -> String) -> PathComponent os -> PathComponent os
pcMap :: forall os.
(String -> String) -> PathComponent os -> PathComponent os
pcMap String -> String
f (PathComponent String
s) = forall os. String -> PathComponent os
PathComponent forall a b. (a -> b) -> a -> b
$ String -> String
f String
s

pcMapF ::
    (Functor f) =>
    (String -> f String) -> PathComponent os -> f (PathComponent os)
pcMapF :: forall (f :: * -> *) os.
Functor f =>
(String -> f String) -> PathComponent os -> f (PathComponent os)
pcMapF String -> f String
f (PathComponent String
s) = forall os. String -> PathComponent os
PathComponent forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> String -> f String
f String
s


class System os where
    -- | The character that separates directories. In the case where more than
    --   one character is possible, 'pathSeparator' is the \'ideal\' one.
    --
    -- >> Posix.isPathSeparator Posix.pathSeparator
    pathSeparator :: Tagged os Char

    -- | The list of all possible separators.
    --
    -- >> Posix.pathSeparator `elem` Posix.pathSeparators
    pathSeparators :: Tagged os [Char]
    pathSeparators = (forall a. a -> [a] -> [a]
:[]) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall os. System os => Tagged os Char
pathSeparator

    -- | Rather than using @(== 'pathSeparator')@, use this. Test if something
    --   is a path separator.
    --
    -- >> Posix.isPathSeparator a == (a `elem` Posix.pathSeparators)
    isPathSeparator :: Tagged os (Char -> Bool)
    isPathSeparator = forall a b c. (a -> b -> c) -> b -> a -> c
flip forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
elem forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall os. System os => Tagged os String
pathSeparators

    splitAbsolute :: Tagged os (MS.State String String)

    canonicalize :: Tagged os (String -> String)

    splitDrive :: Tagged os (MS.State String String)
    genDrive :: Tagged os (Gen String)