-- | Example: 
--      main = 
--        writeFile "test.ppm" $
--          ppm [ [ (255, 0, 0)
--                , (0, 255, 0)
--                , (0, 0, 255)
--                ]
--              , [ (255, 255, 0)
--                , (255, 255, 255)
--                , (0, 0, 0)
--                ]
--              ]
--             
module Codec.Image.PPM (ppm, ppm_p6, ColorArray, Color) where

import Control.Monad.Writer
import Data.Char
import Data.List (intersperse)

data Profile = P3 | P6 deriving (Show)
type Color = (Int, Int, Int)
type ColorArray = [Color]

data PPM = PPM
  {   profile :: Profile
  ,   color :: Int
  ,   columns :: Int
  ,   rows :: Int
  ,   bytes :: ColorArray
  }
  deriving (Show)


def :: PPM
def = PPM P3 255 0 0 []

dump_ppm :: PPM -> String
dump_ppm x = execWriter $ do
  write $ profile x
  br
  write $ columns x
  tell " "
  write $ rows x
  br
  write $ color x
  br
  mapM_ (write_pixel (profile x)) (bytes x)
  where
    write_pixel P3 (r,g,b) = do
      let xs = [r,g,b]
      tell $ concat $ intersperse " " $ map show xs
      br
    
    write_pixel P6 (r,g,b) = do
      let xs = [r,g,b]
      tell $ map chr xs
    
    br = tell "\n"
    
    write :: (Show a) => a -> Writer String ()
    write = tell . show


-- | output a human readable ppm string, i.e. in p3 format
ppm :: [ColorArray] -> String
ppm xs  = dump_ppm $ from_list xs

-- | output a compact ppm string, i.e. in p6 format
ppm_p6 :: [ColorArray] -> String
ppm_p6 xs = dump_ppm $ (from_list xs) {profile = P6}


from_list :: [ColorArray] -> PPM
from_list [] = def
from_list xs = def
  {   columns = length $ head xs
  ,   rows    = length xs
  ,   bytes   = concat xs
  }