content: {-# language FlexibleContexts, RecordWildCards #-}
  -----------------------------------------------------------------------------
  -- |
  -- Copyright   :  (C) 2016 Marco Zocca
  -- License     :  GPL-3 (see LICENSE)
  -- Maintainer  :  zocca.marco gmail
  -- Stability   :  provisional
  -- Portability :  portable
  --
  --
  -- Pretty printing helper functions
  -----------------------------------------------------------------------------
  module Data.Sparse.PPrint (prd, prd0, PrintDense, newline
                             , PPrintOptions(..)
                               -- , prdefR, prdefC
                             , printDN , printCN
                            ) where
  
  import Data.Complex
  import Data.List
  import Text.Printf
  
  import Numeric.Eps
  
  
  
  class PrintDense a where
    -- | Pretty-print with a descriptive header
    prd :: a -> IO ()
    -- | Pretty-print with no header
    prd0 :: a -> IO ()
  
  newline :: IO ()
  newline = putStrLn ""  
  
  
  -- | Pretty printing options: total length in # digits (including the decimal point), # of decimal digits
  data PPrintOptions =
    PPOpts {
       pprintLen, pprintDec, pprintColWidth :: Int
       } deriving (Eq, Show)
  
  -- | Some defaults
  prdefR, prdefC :: PPrintOptions
  prdefR = PPOpts 4 2 7   -- reals
  prdefC = PPOpts 4 2 16  -- complex values
  
  
  -- | Pretty print an array of real numbers
  printDN :: (PrintfArg a, Epsilon a, Ord a) =>
       Int -> Int -> PPrintOptions -> [a] -> String
  printDN l n = printNpad l n f where
    f o x | isNz x = printf (prepD o x) x
          | otherwise = printf "_"
  
  
  -- | Pretty print an array of complex numbers
  printCN :: (PrintfArg a, Epsilon a, Epsilon (Complex a), Ord a) =>
       Int -> Int -> PPrintOptions -> [Complex a] -> String
  printCN l n = printNpad l n f where
    f o x | nearZero (re x) && isNz (imagPart x) =
                 printf (prepD o (imagPart x)++ "i") (aim x)
          | nearZero (imagPart x) && isNz (re x) =
                 printf (prepD o (realPart x)) (re x)
          | isNz x = printf (prepC o x) (re x) (aim x)
          | otherwise = printf "_"
  
  
  
  
  
  
  -- | printf an array of items with padding space to render a fixed column width
  printNpad ::
       Int     -- ^ Length of list to be provided
       -> Int  -- ^ 
       -> (PPrintOptions -> a -> String)
       -> PPrintOptions -> [a] -> String
  printNpad llen nmax f o@PPOpts{..} xxl = commas [h,l] where
    h = commas $ take hlen ll
    l = last ll
    hlen = min (llen-1) (nmax-1)
    ll = unfoldr g (0, xxl) 
    g (i, x:xs) | i<nmax-2 || llen>=nmax-1 = Just (s', sxs)
                | i==nmax-2 = Just (dots', sxs)
                | null xs = Just (s', sxs)
                | otherwise = Just ("", sxs) where                  
                    s = f o x
                    sxs = (succ i, xs)
                    s' = s ++ spaces (n - length s) 
                    dots' = dots ++ spaces (n - length dots)
    g (_, []) = Nothing
    n = pprintColWidth
    dots = " ... "
  
  
  
  
  
  
  -- | printf format string
  prepD :: (Ord t, Epsilon t) => PPrintOptions -> t -> String
  prepD PPOpts{..} x = s where
    s | nearZero x  = "_"
      | abs x > magHi || abs x < magLo = s0 ++ "e"
      | otherwise = s0 ++ "f"
    s0 = concat ["%" , show nl, ".", show nd]
    -- s0 = "%1." ++ show nd
    nl = pprintLen  
    nd = pprintDec 
    nint = nl - nd  -- # of integer digits
    magLo = 10 ** (- fromIntegral nd)
    magHi = 10 ** fromIntegral nint
              
  
  
  -- | printf format string for a Complex
  prepC :: (Epsilon t, Ord t) => PPrintOptions -> Complex t -> String
  prepC opts (r :+ i) = prepD opts r ++ oi where
    oi = concat [s, prepD opts i', "i"]
    s | signum i >= 0 = " + "
      | otherwise = " - "
    i' = abs i
  
  
  
  
      
  
  -- | Helpers
  
  spaces :: Int -> String
  spaces n = replicate n ' '
  
  commas :: [String] -> String    
  commas = intercalate ", "
  
  re :: Complex a -> a
  re = realPart
  
  aim :: Num a => Complex a -> a
  aim = abs . imagPart
  