{-# LANGUAGE BangPatterns, FlexibleInstances #-}
module Stage.Sources
        (addSources)
where
import Model
import FieldElt
import Data.Array.Repa          as R
import Data.Array.Repa.Unsafe   as R
import Data.Vector.Unboxed      (Unbox)


-- | Addition of forces stage for simulation
addSources 
        :: (FieldElt a, FieldSource a, Unbox a)
        => Delta                -- ^ Time delta.
        -> a                    -- ^ Value to insert.
        -> Maybe (SourceDensity a) 
        -> Field a 
        -> IO (Field a)

addSources !delta !value (Just (SourceDensity aim mul)) field
 = {-# SCC addSources #-}
   field `deepSeqArray` 
   do   computeP $ unsafeTraverse field id (insertSource delta value aim mul)

addSources _ _ Nothing field
   = return field


insertSource 
        :: (FieldElt a, FieldSource a) 
        => Delta
        -> a            -- ^ Value to insert
        -> DIM2 -> a 
        -> (DIM2 -> a) 
        -> DIM2 
        -> a

insertSource !delta !value !aim !mul locate !pos
   | aim == pos = addSource delta value (locate pos) mul
   | otherwise  = locate pos
{-# INLINE insertSource #-}


{-# SPECIALIZE addSources 
        :: Delta 
        -> Float
        -> Maybe (SourceDensity Float)
        -> Field Float 
        -> IO (Field Float) #-}

{-# SPECIALIZE addSources 
        :: Delta
        -> (Float, Float)
        -> Maybe (SourceDensity (Float, Float))
        -> Field (Float, Float) 
        -> IO (Field (Float, Float)) #-}


-- FieldSource ----------------------------------------------------------------
class FieldSource a where
        addSource :: Delta -> a -> a -> a -> a

instance FieldSource Float where
        addSource !delta !value !a !mul 
         =  a ~+~ (value * delta * mul)
        {-# INLINE addSource #-}

instance FieldSource (Float, Float) where
        addSource !delta (newA, newB) (a,b) (mulA, mulB)
         = ( a + (newA * delta * (-mulA))
           , b + (newB * delta * (-mulB)))
        {-# INLINE addSource #-}




