module Poseidon.CLI.Summarise where

import           Poseidon.Janno         (BCADAge (..), JannoList (..),
                                         JannoRow (..), JannoRows (..),
                                         Percent (..))
import           Poseidon.MathHelpers   (meanAndSdInteger, meanAndSdRoundTo)
import           Poseidon.Package       (PackageReadOptions (..),
                                         PoseidonPackage (..),
                                         defaultPackageReadOptions,
                                         readPoseidonPackageCollection)
import           Poseidon.Utils         (PoseidonIO, logInfo, uniquePO)

import           Control.Monad.IO.Class (liftIO)
import           Data.List              (group, intercalate, sort, sortBy)
import           Data.Maybe             (mapMaybe)
import           Text.Layout.Table      (asciiRoundS, column, def, expandUntil,
                                         rowsG, tableString, titlesH)

-- | A datatype representing command line options for the summarise command
data SummariseOptions = SummariseOptions
    { SummariseOptions -> [String]
_summariseBaseDirs  :: [FilePath]
    , SummariseOptions -> Bool
_summariseRawOutput :: Bool
    }

pacReadOpts :: PackageReadOptions
pacReadOpts :: PackageReadOptions
pacReadOpts = PackageReadOptions
defaultPackageReadOptions {
      _readOptIgnoreChecksums :: Bool
_readOptIgnoreChecksums      = Bool
True
    , _readOptIgnoreGeno :: Bool
_readOptIgnoreGeno           = Bool
True
    , _readOptGenoCheck :: Bool
_readOptGenoCheck            = Bool
False
    , _readOptOnlyLatest :: Bool
_readOptOnlyLatest           = Bool
True
    }

-- | The main function running the janno command
runSummarise :: SummariseOptions -> PoseidonIO ()
runSummarise :: SummariseOptions -> PoseidonIO ()
runSummarise (SummariseOptions [String]
baseDirs Bool
rawOutput) = do
    [PoseidonPackage]
allPackages <- PackageReadOptions -> [String] -> PoseidonIO [PoseidonPackage]
readPoseidonPackageCollection PackageReadOptions
pacReadOpts [String]
baseDirs
    let jannos :: [JannoRows]
jannos = (PoseidonPackage -> JannoRows) -> [PoseidonPackage] -> [JannoRows]
forall a b. (a -> b) -> [a] -> [b]
map PoseidonPackage -> JannoRows
posPacJanno [PoseidonPackage]
allPackages
    String -> PoseidonIO ()
logInfo String
"Note that only the latest versions of packages are included in the summary"
    IO () -> PoseidonIO ()
forall a. IO a -> ReaderT Env IO a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> PoseidonIO ()) -> IO () -> PoseidonIO ()
forall a b. (a -> b) -> a -> b
$ JannoRows -> Bool -> IO ()
summariseJannoRows ([JannoRows] -> JannoRows
forall a. Monoid a => [a] -> a
mconcat [JannoRows]
jannos) Bool
rawOutput

-- | A function to print meaningful summary information for a list of poseidon samples
summariseJannoRows :: JannoRows -> Bool -> IO ()
summariseJannoRows :: JannoRows -> Bool -> IO ()
summariseJannoRows (JannoRows [JannoRow]
rows) Bool
rawOutput = do
    ([String]
tableH, [[String]]
tableB) <- do
        let tableH :: [String]
tableH = [String
"Summary", String
"Value"]
            tableB :: [[String]]
tableB = [
                [String
"Nr Samples"
                , Int -> String
forall a. Show a => a -> String
show ([JannoRow] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [JannoRow]
rows)],
                [String
"Samples"
                , [String] -> String
paste ([String] -> String)
-> ([JannoRow] -> [String]) -> [JannoRow] -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [String] -> [String]
forall a. Ord a => [a] -> [a]
sort ([String] -> [String])
-> ([JannoRow] -> [String]) -> [JannoRow] -> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (JannoRow -> String) -> [JannoRow] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map JannoRow -> String
jPoseidonID ([JannoRow] -> String) -> [JannoRow] -> String
forall a b. (a -> b) -> a -> b
$ [JannoRow]
rows],
                [String
"Nr Primary Groups"
                , [String] -> String
forall a. Ord a => [a] -> String
uniqueNumber ([String] -> String)
-> ([JannoRow] -> [String]) -> [JannoRow] -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (JannoRow -> String) -> [JannoRow] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map ([String] -> String
forall a. HasCallStack => [a] -> a
head ([String] -> String)
-> (JannoRow -> [String]) -> JannoRow -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. JannoList String -> [String]
forall a. JannoList a -> [a]
getJannoList (JannoList String -> [String])
-> (JannoRow -> JannoList String) -> JannoRow -> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. JannoRow -> JannoList String
jGroupName) ([JannoRow] -> String) -> [JannoRow] -> String
forall a b. (a -> b) -> a -> b
$ [JannoRow]
rows],
                [String
"Primary Groups"
                , String -> [(String, Int)] -> String
printFrequencyString String
", " ([(String, Int)] -> String)
-> ([JannoRow] -> [(String, Int)]) -> [JannoRow] -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [String] -> [(String, Int)]
forall a. Ord a => [a] -> [(a, Int)]
frequency ([String] -> [(String, Int)])
-> ([JannoRow] -> [String]) -> [JannoRow] -> [(String, Int)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (JannoRow -> String) -> [JannoRow] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map ([String] -> String
forall a. HasCallStack => [a] -> a
head ([String] -> String)
-> (JannoRow -> [String]) -> JannoRow -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. JannoList String -> [String]
forall a. JannoList a -> [a]
getJannoList (JannoList String -> [String])
-> (JannoRow -> JannoList String) -> JannoRow -> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. JannoRow -> JannoList String
jGroupName) ([JannoRow] -> String) -> [JannoRow] -> String
forall a b. (a -> b) -> a -> b
$ [JannoRow]
rows],
                [String
"Nr Publications"
                , [String] -> String
forall a. Ord a => [a] -> String
uniqueNumber ([String] -> String)
-> ([JannoRow] -> [String]) -> [JannoRow] -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (JannoList String -> [String]) -> [JannoList String] -> [String]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap JannoList String -> [String]
forall a. JannoList a -> [a]
getJannoList ([JannoList String] -> [String])
-> ([JannoRow] -> [JannoList String]) -> [JannoRow] -> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (JannoRow -> Maybe (JannoList String))
-> [JannoRow] -> [JannoList String]
forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe JannoRow -> Maybe (JannoList String)
jPublication ([JannoRow] -> String) -> [JannoRow] -> String
forall a b. (a -> b) -> a -> b
$ [JannoRow]
rows],
                [String
"Publications"
                , [String] -> String
paste ([String] -> String)
-> ([JannoRow] -> [String]) -> [JannoRow] -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [String] -> [String]
forall a. Ord a => [a] -> [a]
uniquePO ([String] -> [String])
-> ([JannoRow] -> [String]) -> [JannoRow] -> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (JannoList String -> [String]) -> [JannoList String] -> [String]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap JannoList String -> [String]
forall a. JannoList a -> [a]
getJannoList ([JannoList String] -> [String])
-> ([JannoRow] -> [JannoList String]) -> [JannoRow] -> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (JannoRow -> Maybe (JannoList String))
-> [JannoRow] -> [JannoList String]
forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe JannoRow -> Maybe (JannoList String)
jPublication ([JannoRow] -> String) -> [JannoRow] -> String
forall a b. (a -> b) -> a -> b
$ [JannoRow]
rows],
                [String
"Nr Countries"
                , [String] -> String
forall a. Ord a => [a] -> String
uniqueNumber ([String] -> String)
-> ([JannoRow] -> [String]) -> [JannoRow] -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (JannoRow -> Maybe String) -> [JannoRow] -> [String]
forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe JannoRow -> Maybe String
jCountry ([JannoRow] -> String) -> [JannoRow] -> String
forall a b. (a -> b) -> a -> b
$ [JannoRow]
rows],
                [String
"Countries"
                , String -> [(Maybe String, Int)] -> String
printFrequencyMaybeString String
", " ([(Maybe String, Int)] -> String)
-> ([JannoRow] -> [(Maybe String, Int)]) -> [JannoRow] -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Maybe String] -> [(Maybe String, Int)]
forall a. Ord a => [a] -> [(a, Int)]
frequency ([Maybe String] -> [(Maybe String, Int)])
-> ([JannoRow] -> [Maybe String])
-> [JannoRow]
-> [(Maybe String, Int)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (JannoRow -> Maybe String) -> [JannoRow] -> [Maybe String]
forall a b. (a -> b) -> [a] -> [b]
map JannoRow -> Maybe String
jCountry ([JannoRow] -> String) -> [JannoRow] -> String
forall a b. (a -> b) -> a -> b
$ [JannoRow]
rows],
                [String
"Mean age BC/AD"
                , [Double] -> String
meanAndSdInteger ([Double] -> String)
-> ([JannoRow] -> [Double]) -> [JannoRow] -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (BCADAge -> Double) -> [BCADAge] -> [Double]
forall a b. (a -> b) -> [a] -> [b]
map (\(BCADAge Int
x) -> Int -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
x) ([BCADAge] -> [Double])
-> ([JannoRow] -> [BCADAge]) -> [JannoRow] -> [Double]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (JannoRow -> Maybe BCADAge) -> [JannoRow] -> [BCADAge]
forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe JannoRow -> Maybe BCADAge
jDateBCADMedian ([JannoRow] -> String) -> [JannoRow] -> String
forall a b. (a -> b) -> a -> b
$ [JannoRow]
rows],
                [String
"Dating type"
                , String -> [(Maybe JannoDateType, Int)] -> String
forall a. Show a => String -> [(Maybe a, Int)] -> String
printFrequencyMaybe String
", " ([(Maybe JannoDateType, Int)] -> String)
-> ([JannoRow] -> [(Maybe JannoDateType, Int)])
-> [JannoRow]
-> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Maybe JannoDateType] -> [(Maybe JannoDateType, Int)]
forall a. Ord a => [a] -> [(a, Int)]
frequency ([Maybe JannoDateType] -> [(Maybe JannoDateType, Int)])
-> ([JannoRow] -> [Maybe JannoDateType])
-> [JannoRow]
-> [(Maybe JannoDateType, Int)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (JannoRow -> Maybe JannoDateType)
-> [JannoRow] -> [Maybe JannoDateType]
forall a b. (a -> b) -> [a] -> [b]
map JannoRow -> Maybe JannoDateType
jDateType ([JannoRow] -> String) -> [JannoRow] -> String
forall a b. (a -> b) -> a -> b
$ [JannoRow]
rows],
                [String
"Sex distribution"
                , String -> [(JannoSex, Int)] -> String
forall a. Show a => String -> [(a, Int)] -> String
printFrequency String
", " ([(JannoSex, Int)] -> String)
-> ([JannoRow] -> [(JannoSex, Int)]) -> [JannoRow] -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [JannoSex] -> [(JannoSex, Int)]
forall a. Ord a => [a] -> [(a, Int)]
frequency ([JannoSex] -> [(JannoSex, Int)])
-> ([JannoRow] -> [JannoSex]) -> [JannoRow] -> [(JannoSex, Int)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (JannoRow -> JannoSex) -> [JannoRow] -> [JannoSex]
forall a b. (a -> b) -> [a] -> [b]
map JannoRow -> JannoSex
jGeneticSex ([JannoRow] -> String) -> [JannoRow] -> String
forall a b. (a -> b) -> a -> b
$ [JannoRow]
rows],
                [String
"MT haplogroups"
                , String -> [(Maybe String, Int)] -> String
printFrequencyMaybeString String
", " ([(Maybe String, Int)] -> String)
-> ([JannoRow] -> [(Maybe String, Int)]) -> [JannoRow] -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Maybe String] -> [(Maybe String, Int)]
forall a. Ord a => [a] -> [(a, Int)]
frequency ([Maybe String] -> [(Maybe String, Int)])
-> ([JannoRow] -> [Maybe String])
-> [JannoRow]
-> [(Maybe String, Int)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (JannoRow -> Maybe String) -> [JannoRow] -> [Maybe String]
forall a b. (a -> b) -> [a] -> [b]
map JannoRow -> Maybe String
jMTHaplogroup ([JannoRow] -> String) -> [JannoRow] -> String
forall a b. (a -> b) -> a -> b
$ [JannoRow]
rows],
                [String
"Y haplogroups"
                , String -> [(Maybe String, Int)] -> String
printFrequencyMaybeString String
", " ([(Maybe String, Int)] -> String)
-> ([JannoRow] -> [(Maybe String, Int)]) -> [JannoRow] -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Maybe String] -> [(Maybe String, Int)]
forall a. Ord a => [a] -> [(a, Int)]
frequency ([Maybe String] -> [(Maybe String, Int)])
-> ([JannoRow] -> [Maybe String])
-> [JannoRow]
-> [(Maybe String, Int)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (JannoRow -> Maybe String) -> [JannoRow] -> [Maybe String]
forall a b. (a -> b) -> [a] -> [b]
map JannoRow -> Maybe String
jYHaplogroup ([JannoRow] -> String) -> [JannoRow] -> String
forall a b. (a -> b) -> a -> b
$ [JannoRow]
rows],
                [String
"% endogenous DNA"
                , Int -> [Double] -> String
meanAndSdRoundTo Int
2 ([Double] -> String)
-> ([JannoRow] -> [Double]) -> [JannoRow] -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Percent -> Double) -> [Percent] -> [Double]
forall a b. (a -> b) -> [a] -> [b]
map (\(Percent Double
x) -> Double
x) ([Percent] -> [Double])
-> ([JannoRow] -> [Percent]) -> [JannoRow] -> [Double]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (JannoRow -> Maybe Percent) -> [JannoRow] -> [Percent]
forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe JannoRow -> Maybe Percent
jEndogenous ([JannoRow] -> String) -> [JannoRow] -> String
forall a b. (a -> b) -> a -> b
$ [JannoRow]
rows],
                [String
"Nr of SNPs"
                , [Double] -> String
meanAndSdInteger ([Double] -> String)
-> ([JannoRow] -> [Double]) -> [JannoRow] -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Int -> Double) -> [Int] -> [Double]
forall a b. (a -> b) -> [a] -> [b]
map Int -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral ([Int] -> [Double])
-> ([JannoRow] -> [Int]) -> [JannoRow] -> [Double]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (JannoRow -> Maybe Int) -> [JannoRow] -> [Int]
forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe JannoRow -> Maybe Int
jNrSNPs ([JannoRow] -> String) -> [JannoRow] -> String
forall a b. (a -> b) -> a -> b
$ [JannoRow]
rows],
                [String
"Coverage on target"
                , Int -> [Double] -> String
meanAndSdRoundTo Int
2 ([Double] -> String)
-> ([JannoRow] -> [Double]) -> [JannoRow] -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (JannoRow -> Maybe Double) -> [JannoRow] -> [Double]
forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe JannoRow -> Maybe Double
jCoverageOnTargets ([JannoRow] -> String) -> [JannoRow] -> String
forall a b. (a -> b) -> a -> b
$ [JannoRow]
rows],
                [String
"Library type"
                , String -> [(Maybe JannoLibraryBuilt, Int)] -> String
forall a. Show a => String -> [(Maybe a, Int)] -> String
printFrequencyMaybe String
", " ([(Maybe JannoLibraryBuilt, Int)] -> String)
-> ([JannoRow] -> [(Maybe JannoLibraryBuilt, Int)])
-> [JannoRow]
-> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Maybe JannoLibraryBuilt] -> [(Maybe JannoLibraryBuilt, Int)]
forall a. Ord a => [a] -> [(a, Int)]
frequency ([Maybe JannoLibraryBuilt] -> [(Maybe JannoLibraryBuilt, Int)])
-> ([JannoRow] -> [Maybe JannoLibraryBuilt])
-> [JannoRow]
-> [(Maybe JannoLibraryBuilt, Int)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (JannoRow -> Maybe JannoLibraryBuilt)
-> [JannoRow] -> [Maybe JannoLibraryBuilt]
forall a b. (a -> b) -> [a] -> [b]
map JannoRow -> Maybe JannoLibraryBuilt
jLibraryBuilt ([JannoRow] -> String) -> [JannoRow] -> String
forall a b. (a -> b) -> a -> b
$ [JannoRow]
rows],
                [String
"UDG treatment"
                , String -> [(Maybe JannoUDG, Int)] -> String
forall a. Show a => String -> [(Maybe a, Int)] -> String
printFrequencyMaybe String
", " ([(Maybe JannoUDG, Int)] -> String)
-> ([JannoRow] -> [(Maybe JannoUDG, Int)]) -> [JannoRow] -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Maybe JannoUDG] -> [(Maybe JannoUDG, Int)]
forall a. Ord a => [a] -> [(a, Int)]
frequency ([Maybe JannoUDG] -> [(Maybe JannoUDG, Int)])
-> ([JannoRow] -> [Maybe JannoUDG])
-> [JannoRow]
-> [(Maybe JannoUDG, Int)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (JannoRow -> Maybe JannoUDG) -> [JannoRow] -> [Maybe JannoUDG]
forall a b. (a -> b) -> [a] -> [b]
map JannoRow -> Maybe JannoUDG
jUDG ([JannoRow] -> String) -> [JannoRow] -> String
forall a b. (a -> b) -> a -> b
$ [JannoRow]
rows]
                ]
        ([String], [[String]]) -> IO ([String], [[String]])
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ([String]
tableH, [[String]]
tableB)
    let colSpecs :: [ColSpec]
colSpecs = Int -> ColSpec -> [ColSpec]
forall a. Int -> a -> [a]
replicate Int
2 (LenSpec -> Position H -> AlignSpec -> CutMark -> ColSpec
column (Int -> LenSpec
expandUntil Int
60) Position H
forall a. Default a => a
def AlignSpec
forall a. Default a => a
def CutMark
forall a. Default a => a
def)
    if Bool
rawOutput
    then String -> IO ()
putStrLn (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
intercalate String
"\n" [String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
intercalate String
"\t" [String]
row | [String]
row <- [[String]]
tableB]
    else String -> IO ()
putStrLn (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ [ColSpec]
-> TableStyle -> HeaderSpec -> [RowGroup String] -> String
forall a.
Cell a =>
[ColSpec] -> TableStyle -> HeaderSpec -> [RowGroup a] -> String
tableString [ColSpec]
colSpecs TableStyle
asciiRoundS ([String] -> HeaderSpec
titlesH [String]
tableH) [[[String]] -> RowGroup String
forall a. [Row a] -> RowGroup a
rowsG [[String]]
tableB]

-- | A helper function to concat the first N elements of a string list in a nice way
paste :: [String] -> String
paste :: [String] -> String
paste [] = String
"no values"
paste [String]
xs = String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
intercalate String
", " [String]
xs

uniqueNumber :: Ord a => [a] -> String
uniqueNumber :: forall a. Ord a => [a] -> String
uniqueNumber = Int -> String
forall a. Show a => a -> String
show (Int -> String) -> ([a] -> Int) -> [a] -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [a] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length ([a] -> Int) -> ([a] -> [a]) -> [a] -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [a] -> [a]
forall a. Ord a => [a] -> [a]
uniquePO

-- | A helper function to determine the frequency of objects in a list
-- (similar to the table function in R)
frequency :: Ord a => [a] -> [(a,Int)]
frequency :: forall a. Ord a => [a] -> [(a, Int)]
frequency [a]
list = ((a, Int) -> (a, Int) -> Ordering) -> [(a, Int)] -> [(a, Int)]
forall a. (a -> a -> Ordering) -> [a] -> [a]
sortBy (a, Int) -> (a, Int) -> Ordering
forall a b. (Ord a, Ord b) => (a, b) -> (a, b) -> Ordering
sortTupelsBySndDesc ([(a, Int)] -> [(a, Int)]) -> [(a, Int)] -> [(a, Int)]
forall a b. (a -> b) -> a -> b
$ ([a] -> (a, Int)) -> [[a]] -> [(a, Int)]
forall a b. (a -> b) -> [a] -> [b]
map (\[a]
l -> ([a] -> a
forall a. HasCallStack => [a] -> a
head [a]
l, [a] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [a]
l)) ([a] -> [[a]]
forall a. Eq a => [a] -> [[a]]
group ([a] -> [a]
forall a. Ord a => [a] -> [a]
sort [a]
list))

sortTupelsBySndDesc :: (Ord a, Ord b) => (a, b) -> (a, b) -> Ordering
sortTupelsBySndDesc :: forall a b. (Ord a, Ord b) => (a, b) -> (a, b) -> Ordering
sortTupelsBySndDesc (a
a1, b
b1) (a
a2, b
b2)
  | b
b1 b -> b -> Bool
forall a. Ord a => a -> a -> Bool
< b
b2   = Ordering
GT
  | b
b1 b -> b -> Bool
forall a. Ord a => a -> a -> Bool
> b
b2   = Ordering
LT
  | b
b1 b -> b -> Bool
forall a. Eq a => a -> a -> Bool
== b
b2  = a -> a -> Ordering
forall a. Ord a => a -> a -> Ordering
compare a
a1 a
a2
  | Bool
otherwise = String -> Ordering
forall a. HasCallStack => String -> a
error String
"sortTuplesBySndDesc: should never happen"

-- | A helper function to print the output of frequency nicely
printFrequency :: Show a => String -> [(a,Int)] -> String
printFrequency :: forall a. Show a => String -> [(a, Int)] -> String
printFrequency String
_ [] = String
"no values"
printFrequency String
_ [(a, Int)
x] = a -> String
forall a. Show a => a -> String
show ((a, Int) -> a
forall a b. (a, b) -> a
fst (a, Int)
x) String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
": " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show ((a, Int) -> Int
forall a b. (a, b) -> b
snd (a, Int)
x)
printFrequency String
sep ((a, Int)
x:[(a, Int)]
xs) = a -> String
forall a. Show a => a -> String
show ((a, Int) -> a
forall a b. (a, b) -> a
fst (a, Int)
x) String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
": " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show ((a, Int) -> Int
forall a b. (a, b) -> b
snd (a, Int)
x) String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
sep String -> String -> String
forall a. [a] -> [a] -> [a]
++ String -> [(a, Int)] -> String
forall a. Show a => String -> [(a, Int)] -> String
printFrequency String
sep [(a, Int)]
xs

-- | A helper function to print the output of frequency over Maybe values nicely
printFrequencyMaybe :: Show a => String -> [(Maybe a,Int)] -> String
printFrequencyMaybe :: forall a. Show a => String -> [(Maybe a, Int)] -> String
printFrequencyMaybe String
_ [] = String
"no values"
printFrequencyMaybe String
_ [(Maybe a, Int)
x] = Maybe a -> String
forall a. Show a => Maybe a -> String
maybeShow ((Maybe a, Int) -> Maybe a
forall a b. (a, b) -> a
fst (Maybe a, Int)
x) String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
": " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show ((Maybe a, Int) -> Int
forall a b. (a, b) -> b
snd (Maybe a, Int)
x)
printFrequencyMaybe String
sep ((Maybe a, Int)
x:[(Maybe a, Int)]
xs) = Maybe a -> String
forall a. Show a => Maybe a -> String
maybeShow ((Maybe a, Int) -> Maybe a
forall a b. (a, b) -> a
fst (Maybe a, Int)
x) String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
": " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show ((Maybe a, Int) -> Int
forall a b. (a, b) -> b
snd (Maybe a, Int)
x) String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
sep String -> String -> String
forall a. [a] -> [a] -> [a]
++ String -> [(Maybe a, Int)] -> String
forall a. Show a => String -> [(Maybe a, Int)] -> String
printFrequencyMaybe String
sep [(Maybe a, Int)]
xs

-- | A helper function to unwrap a maybe
maybeShow :: Show a => Maybe a -> String
maybeShow :: forall a. Show a => Maybe a -> String
maybeShow (Just a
x) = a -> String
forall a. Show a => a -> String
show a
x
maybeShow Maybe a
Nothing  = String
"n/a"

-- | As printFrequency, but without additional quoting of strings
printFrequencyString :: String -> [(String,Int)] -> String
printFrequencyString :: String -> [(String, Int)] -> String
printFrequencyString String
_ [] = String
"no values"
printFrequencyString String
_ [(String, Int)
x] = (String, Int) -> String
forall a b. (a, b) -> a
fst (String, Int)
x String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
": " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show ((String, Int) -> Int
forall a b. (a, b) -> b
snd (String, Int)
x)
printFrequencyString String
sep ((String, Int)
x:[(String, Int)]
xs) = (String, Int) -> String
forall a b. (a, b) -> a
fst (String, Int)
x String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
": " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show ((String, Int) -> Int
forall a b. (a, b) -> b
snd (String, Int)
x) String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
sep String -> String -> String
forall a. [a] -> [a] -> [a]
++ String -> [(String, Int)] -> String
printFrequencyString String
sep [(String, Int)]
xs

-- | As printFrequencyMaybe, but without additional quoting of strings
printFrequencyMaybeString :: String -> [(Maybe String,Int)] -> String
printFrequencyMaybeString :: String -> [(Maybe String, Int)] -> String
printFrequencyMaybeString String
_ [] = String
"no values"
printFrequencyMaybeString String
_ [(Maybe String, Int)
x] = Maybe String -> String
maybeShowString ((Maybe String, Int) -> Maybe String
forall a b. (a, b) -> a
fst (Maybe String, Int)
x) String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
": " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show ((Maybe String, Int) -> Int
forall a b. (a, b) -> b
snd (Maybe String, Int)
x)
printFrequencyMaybeString String
sep ((Maybe String, Int)
x:[(Maybe String, Int)]
xs) = Maybe String -> String
maybeShowString ((Maybe String, Int) -> Maybe String
forall a b. (a, b) -> a
fst (Maybe String, Int)
x) String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
": " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show ((Maybe String, Int) -> Int
forall a b. (a, b) -> b
snd (Maybe String, Int)
x) String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
sep String -> String -> String
forall a. [a] -> [a] -> [a]
++ String -> [(Maybe String, Int)] -> String
printFrequencyMaybeString String
sep [(Maybe String, Int)]
xs

-- | As maybeShow, but without additional quoting of strings
maybeShowString :: Maybe String -> String
maybeShowString :: Maybe String -> String
maybeShowString (Just String
x) = String
x
maybeShowString Maybe String
Nothing  = String
"n/a"