module WASHClean where

import Data.Char

import WASHData

data CM a = CM ([String] -> a)
instance Monad CM where -- Reader monad
  return x = CM (const x)
  m >>= f  = CM (\strs ->
		 case m of
		   CM mfun -> 
		     case f (mfun strs) of
		       CM ffun ->
			 ffun strs)

class Clean n where
  clean :: n -> CM n

cleanCodeFragList :: [CodeFrag] -> [CodeFrag]
cleanCodeFragList = map g
  where g (EFrag el) = EFrag (cleanElement el)
	g (CFrag cs) = CFrag (cleanContentList cs)
	g cf         = cf

cleanElement :: Element -> Element
cleanElement e@Element{elemName = en, elemContent = ec} =
  if en == "pre"
  then e
  else let ec' = cleanContentList ec in
       e{elemContent = ec'}

cleanContentList :: [Content] -> [Content]
cleanContentList = remove . map g . combine
  where g c = case c of CElement{celem = el} -> CElement{celem = cleanElement el}
			CText{ctext = et}    -> CText{ctext = et { textString = cleanText (textString et) }}
			CCode{ccode = ec}    -> CCode{ccode = cleanCodeFragList ec}
			_ -> c
	combine (CText {ctext = t1} : CText {ctext = t2} : rest ) = 
		combine (CText {ctext = Text {textString = textString t1++ textString t2, textMode = textMode t1}} : rest)
	combine (x : xs) = x : combine xs
	combine [] = []
	remove  (CText{ctext = tt} : rest) | textString tt == " " = remove rest
	-- remove  (CText{ctext = tt} : rest@(CElement{} : _)) = CText{ctext = dropRight tt} : remove rest
	-- remove  (e@CElement{} : (CText{ctext = tt} : rest)) = e : remove (CText{ctext = dropLeft tt} : rest)
	remove  (x : rest) = x : remove rest
	remove  [] = []

cleanText "" = ""
cleanText xs@[x] | isSpace x = " "
		 | otherwise = xs
cleanText (x : ys@(y : _)) | isSpace x = if isSpace y 
					 then cleanText ys
					 else ' ' : cleanText ys
			   | otherwise = x : cleanText ys

dropRight tt = tt { textString = reverse (dropWhile isSpace (reverse (textString tt))) }
dropLeft  tt = tt { textString = dropWhile isSpace (textString tt) }
