-- |
-- Module: Graphics.Chalkboard.Array
-- Copyright: (c) 2009 Andy Gill
-- License: BSD3
--
-- Maintainer: Andy Gill <andygill@ku.edu>
-- Stability: unstable
-- Portability: ghc
--
-- This module supports basic ascii drawing of 'Board's.
--

module Graphics.Chalkboard.Ascii 
	( toAscii, toCount ) 
  where

import Data.Array

import Graphics.Chalkboard.Board
import Graphics.Chalkboard.Array
import Graphics.Chalkboard.Types
import Graphics.Chalkboard.Color

-- | 'toAscii' generates a board of ascii characters, where each char is two pixels, one wide and two high.

toAscii :: (Int,Int) -> Board Gray -> [String]
toAscii = toAsciiWithPen $ \ v v' -> case (sampleInk v,sampleInk v') of
		      (NoInk,NoInk) -> ' '
		      (NoInk,SomeInk) -> '.'
		      (NoInk,MostInk) -> '_'
		      (SomeInk,NoInk) -> head "'"
		      (SomeInk,SomeInk) -> ':'
		      (SomeInk,MostInk) -> ';'
		      (MostInk,NoInk) -> '"'
		      (MostInk,SomeInk) -> '?'
		      (MostInk,MostInk) -> '%'


-- | 'toCount' generates a board of ascii characters, where each char is two pixels, one wide and two high.
-- we uses digits 1 .. 9, then 0 (highest) to represent intensity, adding the two pixels for each char.

toCount :: (Int,Int) -> Board Gray -> [String]
toCount = toAsciiWithPen $ \ v v' -> 
			case show (ceiling ((v + v') * 5) :: Int) of
			   "0"  -> ' '
			   [c]  -> c
			   "10" -> '0'
			   _    -> '?'

toAsciiWithPen :: (Gray -> Gray -> Char) -> (Int,Int) -> Board Gray -> [String]
toAsciiWithPen pen (x_dim,y_dim) board = [
	[	let v = arr' ! (x,y)
		    v' = arr' ! (x,y')
		in pen v v'
	|	x <- [0..x_dim]
	]
	|	(y,y') <- join [y_dim', y_dim'-2 ..]
	]
	where arr = boardToArray (x_dim,y_dim') 2 board
	      arr' = floydSteinberg sampleT arr
	      y_dim' = if even y_dim then succ y_dim else y_dim
	      join (x:xs) | x < 0     = [] 
			  | otherwise = (x,x-1) : join xs
	      join _ = error "fatal error"

data Ink = NoInk | SomeInk | MostInk

sampleT :: UI -> UI
sampleT n
  | n <= 0.33 = 0.15
  | n <= 0.67 = 0.60
  | otherwise = 1


sampleInk :: UI -> Ink
sampleInk n 
  | n <= 0.33 = MostInk
  | n <= 0.67 = SomeInk
  | otherwise = NoInk