module Test.SBench.Space.Single.Test
    ( getProfile
    , getMaxMem
    , getMaxMemWith
    , getMemLine
    , getMemLineWith
    )
  where

import System.FilePath ( FilePath )

import Test.SBench.Space.Single.MakeExecutable ( make )
import Test.SBench.Space.Single.RunExecutable ( run )
import qualified Test.SBench.Space.Single.ExploreProfile as Explore ( getMaxMem, getMemLine )
import Test.SBench.Options ( TestOpts(..), NormalInput, MemSize(..), MemUnit(..), Title, opts2string, EvalMod(..) )
import Test.SBench.STerm ( Algorithm(..), Data )
import Test.SBench.Space.OptionSet ( setRepetitions, addCC, defltTestOpts, setNfInput, setMemSizes )
import Test.SBench.File.FileOps ( series2sbench' )


-- | Create only the heap profile.
getProfile :: TestOpts -> Algorithm (a -> b) -> Data a 
    -> FilePath -> IO FilePath
getProfile topts alg arg file = make topts alg arg file >>= run topts


-- | Get the maximal heap occupied by the algorithm.
--   Since the algorithms comes with a cost center annotation this is used to
--   explore what heap consumption should be measured (here: all heap directly
--   or indirectly used by the given algorithm).
getMaxMem ::    NormalInput         -- ^ Shall input be normalized first? (Boolean value)
             -> Algorithm (a -> b)  -- ^ The algorithm to test
             -> Data a              -- ^ The test input
             -> FilePath            -- ^ File the program generated for measurements is stored to.
                                    --   More precise: the files, i.e. source code, executable,
                                    --   heap profile, intermediate files during build
             -> IO Integer          -- ^ Maximal heap used.
getMaxMem nfinp alg = 
  getMaxMemWith (setNfInput nfinp $ setMemSizes [Stack 500 M] $ setRepetitions 1 $ addCC alg $ defltTestOpts) alg

-- | As 'getMaxMem', but 'TestOpts' can be set by the user.
getMaxMemWith :: TestOpts -> Algorithm (a -> b) -> Data a -> FilePath -> IO Integer
getMaxMemWith topts alg arg file = getProfile topts alg arg file >>= Explore.getMaxMem


-- | The function generates a heap profile, returns the heapconsumption over time as series and
--   also stores the series as an .sbench file.
getMemLine :: NormalInput              -- ^ Shall input be normalized first? (Boolean value)
           -> (FilePath, Title)        -- ^ Name of the generated .sbench file and all 
                                       --   intermediate files (e.g. .hs, .hp)
           -> Algorithm (a -> b)       -- ^ The algorithm to test
           -> Data a                   -- ^ The test input
           -> IO [(Double, Integer)]
getMemLine nfinp store alg = 
  getMemLineWith (setNfInput nfinp $ setMemSizes [Stack 500 M] $ setRepetitions 1 $ addCC alg $ defltTestOpts) store alg

-- As 'getMemLine', but 'TestOpts' can be set by the user.
getMemLineWith :: TestOpts -> (FilePath, Title) -> Algorithm (a -> b) -> Data a -> IO [(Double, Integer)]
getMemLineWith topts (file, title) alg arg = do
    s <- getProfile topts alg arg file >>= Explore.getMemLine
    series2sbench' (opts2string (cOpts topts), show (rOpts topts)) (Just (if (nfInp topts) then NF else WHNF)) alg arg title file s 
    return s