```-- |
-- Module: Graphics.Chalkboard.Array
-- Copyright: (c) 2009 Andy Gill
--
-- Maintainer: Andy Gill <andygill@ku.edu>
-- Stability: unstable
-- Portability: ghc
--
-- Boards are the principal type for our images. The are conceptually functions from
-- 2D coordinates to values, typically a color.
--
-- Common Boards include
--
-- * @Board Bool@           -- A masking @Board@, or region.
--
-- * @Board RGB@	    -- @Color Board@
--
-- * @Board (Alpha RGB)@    -- A @Color Board@ with alpha (transparency) values.
--
-- * @Board (Maybe a)@      -- A @Board@ with binary transparency.
--
-- * @Board (Maybe Color)@  -- A @Color Board@ with binary transparency.
--
-- * @Board Point@          -- A @Board@ (or field) of @Point@ values.
--

module Graphics.Chalkboard.Board
( -- * The Board datatype
Board
-- * looking up a point on the @Board@.
, lookup
-- * Creating @Board@s.
, coord
-- * Translations on a @Board@.
, scale
, scaleXY
, move
, rotate
--
, crop
, Applicative(..)
) where

import Prelude hiding (lookup)

import Graphics.Chalkboard.Utils
import Graphics.Chalkboard.Types

import Control.Applicative

-- | '''Board''' is our primary data type, an infinite flat surface (or R2 field) of values.
-- Conceptually, @Board a = Point -> a@.
data Board a = Board ((R,R) -> a)
-- TODO: consider have a ConstantBoard

lookup :: Board a -> (R,R) -> a
lookup (Board f) = f

-- Board functionals

instance Scale (Board a) where
scale n (Board f) = Board \$ \ (x,y) -> f (x / n,y / n)

-- | move a Board by specified vector.
move :: (R,R) -> Board a -> Board a
move (xd,yd) (Board f) = Board \$ \ (x,y) -> f (x - xd,y - yd)

-- | A non-overloaded version of 'scale' which takes a independent x and y coordinate.
scaleXY :: (R,R) -> Board a -> Board a
scaleXY (xn,yn) (Board f) = Board \$ \ (x,y) -> f (x / xn,y / yn)

-- | rotate the Board.
rotate :: Radian -> Board a -> Board a
rotate theta (Board f) = Board \$ \ (x,y) -> f (cos theta * x - sin theta * y,
sin theta * x + cos theta * y)

-- | 'crop' crops a Board, based on a masking Board.
crop :: Board Bool -> Board a -> Board (Maybe a)

-- board Generators

-- | 'coord' field or 'Board', where each point is its own coordinate in R2.
coord :: Board Point
coord = Board id

-- | build a rectangle mask or region.
maskFor :: (Point,Point) -> Board Bool
maskFor (p1,p2) = fmap (insideRegion (p1,p2)) coord

-- | build a circular mask or region, with a circle of radius @R@, and center @Point@.
circularMaskFor :: Point -> R -> Board Bool
circularMaskFor p r = fmap (insideCircle p r) coord

instance Functor Board where
fmap f (Board fn) = Board (f . fn)

instance Applicative Board where
pure a = Board \$ \ _ -> a
(Board f) <*> (Board a) = Board (\ (x,y) -> f (x,y) \$ a (x,y))

instance (Over c) => Over (Board c) where
over = liftA2 over

```