{-# OPTIONS_HADDOCK hide #-}

-- | Breaks a text up into a list of texts at newline chars. The maximum 
-- length or word count of a element of the list is given by parameters.
-- So the element may contain multiple newlines.
module Language.Hanspell.TextLines
    ( linesByLength
    , linesByWordCount
    ) where

import Data.List

-- | Line-wrapped break up to character count.
linesByLength :: Int -> String -> [String]
linesByLength :: Int -> String -> [String]
linesByLength Int
maxChars =
    ([String] -> String) -> [[String]] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map [String] -> String
unlines ([[String]] -> [String])
-> (String -> [[String]]) -> String -> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [[String]] -> [[String]]
forall a. [a] -> [a]
reverse ([[String]] -> [[String]])
-> (String -> [[String]]) -> String -> [[String]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([String] -> [String]) -> [[String]] -> [[String]]
forall a b. (a -> b) -> [a] -> [b]
map [String] -> [String]
forall a. [a] -> [a]
reverse ([[String]] -> [[String]])
-> (String -> [[String]]) -> String -> [[String]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Int, Int, [String], [[String]]) -> [[String]]
forall (t :: * -> *) a b a.
Foldable t =>
(a, b, t a, [t a]) -> [t a]
merge ((Int, Int, [String], [[String]]) -> [[String]])
-> (String -> (Int, Int, [String], [[String]]))
-> String
-> [[String]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. 
        ((Int, Int, [String], [[String]])
 -> String -> (Int, Int, [String], [[String]]))
-> (Int, Int, [String], [[String]])
-> [String]
-> (Int, Int, [String], [[String]])
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' (Int, Int, [String], [[String]])
-> String -> (Int, Int, [String], [[String]])
mergeLine (Int
maxChars,Int
0,[],[]) ([String] -> (Int, Int, [String], [[String]]))
-> (String -> [String])
-> String
-> (Int, Int, [String], [[String]])
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> [String]
lines
  where
    mergeLine :: (Int,Int,[String],[[String]])
              -> String
              -> (Int,Int,[String],[[String]])
    mergeLine :: (Int, Int, [String], [[String]])
-> String -> (Int, Int, [String], [[String]])
mergeLine (Int
maxChars,Int
headsLength,[String]
heads,[[String]]
merged) String
aLine = 
        if Int
lineLength Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
headsLength Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
maxChars Bool -> Bool -> Bool
&& Bool -> Bool
not ([String] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [String]
heads) 
           then (Int
maxChars,Int
lineLength,[String
aLine],[String]
heads[String] -> [[String]] -> [[String]]
forall a. a -> [a] -> [a]
:[[String]]
merged)
           else (Int
maxChars,Int
lineLength Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
headsLength,String
aLineString -> [String] -> [String]
forall a. a -> [a] -> [a]
:[String]
heads,[[String]]
merged)
        where lineLength :: Int
lineLength = String -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length String
aLine Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1

-- | Line-wrapped break up to word count.
linesByWordCount :: Int -> String -> [String]
linesByWordCount :: Int -> String -> [String]
linesByWordCount Int
maxWords =
    ([String] -> String) -> [[String]] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map [String] -> String
unlines ([[String]] -> [String])
-> (String -> [[String]]) -> String -> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [[String]] -> [[String]]
forall a. [a] -> [a]
reverse ([[String]] -> [[String]])
-> (String -> [[String]]) -> String -> [[String]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([String] -> [String]) -> [[String]] -> [[String]]
forall a b. (a -> b) -> [a] -> [b]
map [String] -> [String]
forall a. [a] -> [a]
reverse ([[String]] -> [[String]])
-> (String -> [[String]]) -> String -> [[String]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Int, Int, [String], [[String]]) -> [[String]]
forall (t :: * -> *) a b a.
Foldable t =>
(a, b, t a, [t a]) -> [t a]
merge ((Int, Int, [String], [[String]]) -> [[String]])
-> (String -> (Int, Int, [String], [[String]]))
-> String
-> [[String]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. 
        ((Int, Int, [String], [[String]])
 -> String -> (Int, Int, [String], [[String]]))
-> (Int, Int, [String], [[String]])
-> [String]
-> (Int, Int, [String], [[String]])
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' (Int, Int, [String], [[String]])
-> String -> (Int, Int, [String], [[String]])
mergeLine (Int
maxWords,Int
0,[],[]) ([String] -> (Int, Int, [String], [[String]]))
-> (String -> [String])
-> String
-> (Int, Int, [String], [[String]])
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> [String]
lines
  where
    mergeLine :: (Int,Int,[String],[[String]])
              -> String
              -> (Int,Int,[String],[[String]])
    mergeLine :: (Int, Int, [String], [[String]])
-> String -> (Int, Int, [String], [[String]])
mergeLine (Int
maxWords,Int
headsWords,[String]
heads,[[String]]
merged) String
aLine = 
        if Int
xWords Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
headsWords Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
maxWords Bool -> Bool -> Bool
&& Bool -> Bool
not ([String] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [String]
heads) 
           then (Int
maxWords,Int
xWords,[String
aLine],[String]
heads[String] -> [[String]] -> [[String]]
forall a. a -> [a] -> [a]
:[[String]]
merged)
           else (Int
maxWords,Int
xWords Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
headsWords,String
aLineString -> [String] -> [String]
forall a. a -> [a] -> [a]
:[String]
heads,[[String]]
merged)
        where xWords :: Int
xWords = [String] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length (String -> [String]
words String
aLine)

-- Add the heads left to the merged heads list
merge :: (a, b, t a, [t a]) -> [t a]
merge (a
_,b
_,t a
heads,[t a]
merged) = if t a -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null t a
heads then [t a]
merged else t a
headst a -> [t a] -> [t a]
forall a. a -> [a] -> [a]
:[t a]
merged