{-# LANGUAGE TypeSynonymInstances, TypeOperators, FlexibleInstances
           , GeneralizedNewtypeDeriving, TypeFamilies
           , MultiParamTypeClasses, UndecidableInstances
  #-}
{-# OPTIONS_GHC -Wall #-}
----------------------------------------------------------------------
-- |
-- Module      :  Shady.Color
-- Copyright   :  (c) Conal Elliott 2009
-- License     :  AGPLv3
-- 
-- Maintainer  :  conal@conal.net
-- Stability   :  experimental
-- 
-- Simple colors
----------------------------------------------------------------------

module Shady.Color
  (
  -- * Basics
    Color, colorToR4, r4ToColor, rgba, rgb, colorR, colorG, colorB, colorA
  -- * Color operations
  , overC, over
  -- * Some colors
  , black, white, red, green, blue, clear, grey, gray
  -- * Conversion to color
  , HasColor(..)
  ) where

import Data.Monoid (Monoid(..))
import Control.Applicative (liftA2)

import Control.Compose ((~>))

import Data.VectorSpace
import Data.NumInstances ()

import Data.Boolean

import Shady.Misc (Unop, Binop)
import Shady.Language.Exp


-- TODO: Vector space instance


{--------------------------------------------------------------------
    Basics
--------------------------------------------------------------------}

type Float4E = (FloatE,FloatE,FloatE,FloatE)

-- | Color, as RGBA
newtype Color = C { unC :: Float4E }
  deriving ( Eq,Ord,Show,Num,Fractional,Floating
           , AdditiveGroup, InnerSpace )

-- VectorSpace has an associated type, which @deriving@ currently doesn't handle.
instance VectorSpace Color where
  type Scalar Color = Scalar (Float4E)
  (*^) s = inC ((*^) s)

-- | Representation conversion
colorToR4 :: Color -> R4E
colorToR4 (C (r,g,b,a)) = vec4 r g b a

-- | Representation conversion
r4ToColor :: R4E -> Color
r4ToColor = C . un4

inC :: Unop (Float4E) -> Unop Color
inC = unC ~> C

inC2 :: Binop (Float4E) -> Binop Color
inC2 = unC ~> inC

-- | Color from red, green, blue, alpha components
rgba :: R1 :=> R1 :=> R1 :=> R1 :=> Color
rgba r g b a = C (r,g,b,a)

-- | Color from red, green, blue components
rgb :: R1 :=> R1 :=> R1 :=> Color
rgb r g b = rgba r g b 1


-- | Extract the red component
colorR :: Color -> FloatE
colorR (C (r,_,_,_)) = r

-- | Extract the green component
colorG :: Color -> FloatE
colorG (C (_,g,_,_)) = g

-- | Extract the blue component
colorB :: Color -> FloatE
colorB (C (_,_,b,_)) = b

-- | Extract the alpha component
colorA :: Color -> FloatE
colorA (C (_,_,_,a)) = a


{--------------------------------------------------------------------
    Color operations
--------------------------------------------------------------------}

-- | Overlay on two colors
overC :: Binop Color
overC top bot = top ^+^ (1 - colorA top) *^ bot

-- | Pointwise 'overC', e.g., for images.
over :: Binop (p->Color)
over = liftA2 overC


{--------------------------------------------------------------------
    Some colors
--------------------------------------------------------------------}

-- | Some colors
black, white, red, green, blue, clear :: Color
black = grey 0
white = grey 1

red   = rgb 1 0 0
green = rgb 0 1 0
blue  = rgb 0 0 1

clear = rgba 0 0 0 0

-- | Shade of grey
grey, gray :: R1 :=> Color
grey x = rgb x x x
gray = grey


{--------------------------------------------------------------------
    Instances
--------------------------------------------------------------------}

instance Monoid Color where
  mempty  = clear
  mappend = overC

instance IfB BoolE Color where
  ifB = inC2 . ifB

{--------------------------------------------------------------------
    Conversion to color
--------------------------------------------------------------------}

class HasColor a where toColor :: a -> Color

instance HasColor Color where toColor = id
instance HasColor BoolE where toColor = boolean nonWhite white

nonWhite :: Color
nonWhite = clear
  -- rgb 0 0.2 0
  -- dark green
  -- clear -- black