content: {-# LANGUAGE ScopedTypeVariables #-}
  
  module Main where
  
  import Config
  import QuickSort
  
  import Control.Monad
  import Data.Array.IO
  import Data.Label
  import Data.Maybe
  import System.Random
  import Text.Read (readMaybe)
  
  import Data.Array.Accelerate.Examples.Internal
  import qualified Data.Array.Accelerate                              as A
  
  main :: IO ()
  main = do
    beginMonitoring
    (conf, opts, rest) <- parseArgs options defaults header footer
    let qsort = quicksort $ get optBackend opts
  
    case (get configRandomSize conf, rest) of
      (Nothing, [path]) -> do
        -- Read input from file
        file <- readFile path
        let input = map (fromMaybe (error "Parse error. Input file should contain integers separated by spaces") . readMaybe) $ words file
        let result = A.toList $ qsort $ A.fromList (A.Z A.:. length input) input
        putStrLn $ unwords $ map show result
      (Just size, _) -> do
        -- Do multiple runs using a random input
        -- For later runs, the program does not have to be recompiled
        replicateM_ 10 $ randomRun qsort size
      _ -> do
        putStrLn "Usage: accelerate-quicksort input.txt"
        putStrLn "Or:    accelerate-quicksort --size 1000"
  
  randomRun :: (A.Vector Int -> A.Vector Int) -> Int -> IO ()
  randomRun qsort size = do
    putStrLn $ "Sorting " ++ show size ++ " elements"
    input <- shuffle [1 .. size]
    let result = A.toList $ qsort $ A.fromList (A.Z A.:. length input) input
    putStrLn $ unwords (map show $ take 30 result) ++ (if size <= 30 then "" else " ...")
    putStrLn ""
  
  -- | /O(N)/ Randomly shuffle a list
  -- From https://wiki.haskell.org/Random_shuffle
  --
  shuffle :: forall a. [a] -> IO [a]
  shuffle xs = do
    let n = length xs
    ar <- newListArray (1,n) xs :: IO (IOArray Int a)
    forM [1..n] $ \i -> do
        j <- randomRIO (i,n)
        vi <- readArray ar i
        vj <- readArray ar j
        writeArray ar j vi
        return vj
  
  