{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeSynonymInstances #-}
{-# LANGUAGE FlexibleInstances #-}
module Portager (
    module Portager.DSL
  , PortageR
  , portager
  , runPortageR
) where

import Control.Monad.Identity (Identity, runIdentity)
import Control.Monad.Trans.Reader (ReaderT, runReaderT)

import Data.Maybe (mapMaybe)
import Data.String (IsString(..))
import Data.Text (Text)
import qualified Data.Text as Text (lines, stripPrefix)
import qualified Data.Text.IO as Text (readFile)

import Portager.Options (Options(..), WorldSet, withOptions)
import Portager.Writes (createPortageSetConfig, writePortageSetConfigs)
import Portager.DSL

type PortageR a = ReaderT PortagerConfiguration Identity a

-- |Triggers Orphan Instances Warning. 
-- It seems that wrapping it in a newtype is not worth the trouble.
instance IsString a => IsString (PortageR a) where
  fromString = return . fromString

runPortageR :: PortagerConfiguration -> ReaderT PortagerConfiguration Identity a -> a
runPortageR cfg r = runIdentity $ runReaderT r cfg

parseWorldSets :: Text -> [WorldSet]
parseWorldSets = mapMaybe (Text.stripPrefix "@") . Text.lines

readWorldSets :: FilePath -> IO [WorldSet]
readWorldSets = fmap parseWorldSets . Text.readFile

portager :: PortagerConfiguration -> [PortageR PackageSet] -> IO ()
portager cfg ps = withOptions $ \opts -> do
  ws <- readWorldSets (_worldSets opts)
  runReaderT (writePortageSetConfigs ws $ map createPortageSetConfig $ runPortageR cfg $ sequence ps) opts