genCommands :: TestConfig -> StdGen -> IO (Interaction,StdGen)
genCommands c g = return$ runCommandGenDefault g$
               (replicateM (nPerProcessInteractions c)$ permute [0..nProcesses c-1])
               >>= mapM (uncurry (genInteraction c)) . concat . map (zip [0..])
               >>= foldM mergeI []
  where
    permute :: [a] -> CommandGen [a]
    permute ls = go (length ls) ls
      where
        go _ [] = return []
        go _ [x] = return [x]
        go len (x:xs) = do
             i <- getRandomR (0,len-2)
             let (x',xs') = swapAt i x xs
             xs'' <- go (len-1) xs'
             return$ x' : xs''

        swapAt :: Int -> a -> [a] -> (a,[a])
        swapAt 0 y (x:xs) = (x,y:xs)
        swapAt i y (x:xs) = second (x:)$ swapAt (i-1) y xs
        swapAt _ y [] = (y,[])

-- | An interaction is a list of commands for a given process.
-- Because an interaction might be the result of merging simpler
-- interactions, each command is attached with an identifier of the
-- simplest interaction that contained it. 
--
-- @[(interaction_id,(destinatary_process_ids,command))]@
--
-- The purpose of the interaction identifier is to allow to shrink
-- a failing test case by removing the interactions that do not affect 
-- the bug reproduction (see function 'shrink').
genCommands :: TestConfig -> StdGen -> IO (Interaction,StdGen)
genCommands c g = return$ runCommandGenDefault g$
               (replicateM (nPerProcessInteractions c)$ permute [0..nProcesses c-1])
               >>= mapM (uncurry (genInteraction c)) . concat . map (zip [0..])
               >>= foldM mergeI []
  where
    permute :: [a] -> CommandGen [a]
    permute ls = go (length ls) ls
      where
        go _ [] = return []
        go _ [x] = return [x]
        go len (x:xs) = do
             i <- getRandomR (0,len-2)
             let (x',xs') = swapAt i x xs
             xs'' <- go (len-1) xs'
             return$ x' : xs''

        swapAt :: Int -> a -> [a] -> (a,[a])
        swapAt 0 y (x:xs) = (x,y:xs)
        swapAt i y (x:xs) = second (x:)$ swapAt (i-1) y xs
        swapAt _ y [] = (y,[])

-- | An interaction is a list of commands for a given process.
-- Because an interaction might be the result of merging simpler
-- interactions, each command is attached with an identifier of the
-- simplest interaction that contained it. 
--
-- @[(interaction_id,(destinatary_process_ids,command))]@
--
-- The purpose of the interaction identifier is to allow to shrink
-- a failing test case by removing the interactions that do not affect 
-- the bug reproduction (see function 'shrink').
genCommands c g = return$ runCommandGenDefault g$
               (replicateM (nPerProcessInteractions c)$ permute [0..nProcesses c-1])
               >>= mapM (uncurry (genInteraction c)) . concat . map (zip [0..])
               >>= foldM mergeI []
  where
    permute :: [a] -> CommandGen [a]
    permute ls = go (length ls) ls
      where
        go _ [] = return []
        go _ [x] = return [x]
        go len (x:xs) = do
             i <- getRandomR (0,len-2)
             let (x',xs') = swapAt i x xs
             xs'' <- go (len-1) xs'
             return$ x' : xs''

        swapAt :: Int -> a -> [a] -> (a,[a])
        swapAt 0 y (x:xs) = (x,y:xs)
        swapAt i y (x:xs) = second (x:)$ swapAt (i-1) y xs
        swapAt _ y [] = (y,[])

-- | An interaction is a list of commands for a given process.
-- Because an interaction might be the result of merging simpler
-- interactions, each command is attached with an identifier of the
-- simplest interaction that contained it. 
--
-- @[(interaction_id,(destinatary_process_ids,command))]@
--
-- The purpose of the interaction identifier is to allow to shrink
-- a failing test case by removing the interactions that do not affect 
-- the bug reproduction (see function 'shrink').