--simple text processing tools----------------------------
--defs. follow Bird/Wadler and are not equivalent to Prelude

-------------------------------------------- type synomyms
type Text = String
type Line = String
type Word = String
type Para = [Line]

------------------------------------------examples

microText =
 "Stille Nacht, \n heilige Nacht, \n\n alles schlaeft,\n einsam wacht...\n"

headline =
  "\nWeihnachten in Salzburg"

{-----------------------------------text as lines, preliminary

asLines:: Text->[Line]
asLines  = foldr break_on_newline [[]]
  where break_on_newline:: Char->[Line]->[Line]
        break_on_newline c ls
          |c == '\n' = []:ls                     --new group
          |otherwise = (c:(head ls)) : (tail ls) --add to group

--------------------------------------------------------------}

------------------------------allgemeines break_on fuer Listen
                           --behandelt break-elem als Separator

break_on:: Eq a => a->a->[[a]]->[[a]]
break_on b c ls
   |c == b    = []:ls                     --new group
   |otherwise = (c:(head ls)) : (tail ls) --add to group

-----------------------------------------------text as lines

asLines:: Text->[Line]
asLines  = foldr (break_on '\n') [[]]

-----------------------------------------------lines as words
                                             --no empty words

asWords:: Line->[Word]
asWords = filter (/= []) . foldr (break_on ' ') [[]]

---------------------------------------line lists as paragraphs
                                               --no empty lines

asParas:: [Line]->[Para]
asParas = filter (/= []) . foldr (break_on []) [[]]

-------------------------------allgemeines concWith fuer Listen

concWith:: a->[a]->[a]->[a]
concWith x ys zs = ys ++ [x] ++ zs

-----------------------------------------------Umkehrfunktionen
                                        --re-insert Separatoren
                                  --erfordern nichtleere Listen
                                --wg. filter nicht exakt invers

unLines:: [Line]->Text
unLines = foldr1 (concWith '\n')

unWords:: [Word]->Line
unWords = foldr1 (concWith ' ')

unParas:: [Para]->[Line]
unParas = foldr1 (concWith [])

-----------------------------------------------Kombinationen

parse:: Text->[[[Word]]]
parse = map(map asWords) . asParas . asLines

unparse:: [[[Word]]]->Text
unparse = unLines . unParas . map(map unWords)

simplify:: Text->Text        --entferne redundante Separatoren
simplify = unparse . parse

countLines = length . asLines
countWords = length . concat. map asWords . asLines
countParas = length . asParas . asLines

-------------------------------------------------------------
------------------------------------------simple Layout tools

--Textblock = Char-Rechteck, d.h. Folge von gleichlangen Zeilen
                                    
type Block = [Line]                              --type synonym 

----------------------------------------------Hilfsfunktionen

copy:: Int->a->[a]                --Liste mit n-mal elem                    
copy (n+1) elem = elem : copy n elem
copy _ _ = []

ljustify:: Int->a->[a]->[a]    --normiert Liste auf Laenge n
                               --rechts Abschneiden/Auffuellen      
ljustify n filler list 
      = take n list ++ copy (n - (length list)) filler

----------------------------line lists as height*width blocks

asBlock:: Int->Int->[Line]->Block
asBlock height width
       = ljustify height (copy width ' ')           --Hoehe
               . map (ljustify width ' ')           --Breite

----------------------------------Komposition von Textbloecken

combHori, combVerti:: Block->Block->Block

combHori = zipWith (++)          --requires equal heights!!!
combVerti = (++)                 --requires equal widths!!!

---------------------------------------------Beispiel Layouts

layout1 =
  (putStr.unLines) 
    (combVerti 
       (asBlock 1 30 []) 
       (combVerti 
          (((asBlock 2 30).asLines.simplify) headline)     
          (((asBlock 6 30).asLines.simplify) microText))) 


layout2 =
  (putStr.unLines) 
   (combVerti 
    (asBlock 1 34 []) 
    (combVerti 
     (((asBlock 2 34).asLines.simplify) headline)
     (combHori     
      (((asBlock 3 17).asLines.simplify) microText)
      (((asBlock 3 17).(drop 3).asLines.simplify) microText)))) 

{- was so aussieht:

Hugs session for:
/usr/local/lib/hugs/lib/Prelude.hs
text_proc
Main> layout1
                              
Weihnachten in Salzburg       
                              
Stille Nacht,                 
heilige Nacht,                
                              
alles schlaeft,               
einsam wacht...               
                              
Main> layout2
                                  
Weihnachten in Salzburg           
                                  
Stille Nacht,    alles schlaeft,  
heilige Nacht,   einsam wacht...  

------------------------------------------------------------}
