-- | Sum up all the waves at a particular point.
waves :: Degree -> Acc (Scalar Phi) -> Exp R2 -> Exp R
waves degree phi x = wrap $ waver degree 0
  where
    waver :: Int -> Exp Float -> Exp Float
    waver n acc
      | n == 0    = acc
      | otherwise = waver (n - 1) (acc + wave (A.constant (fromIntegral n) * A.the phi) x)

    wrap n
      = let n_  = A.truncate n :: Exp Int
            n'  = n - A.fromIntegral n_
        in
        (n_ `rem` 2 A./=* 0) A.? (1-n', n')


-- | Generate the value for a single wave.
waves :: Degree -> Acc (Scalar Phi) -> Exp R2 -> Exp R
waves degree phi x = wrap $ waver degree 0
  where
    waver :: Int -> Exp Float -> Exp Float
    waver n acc
      | n == 0    = acc
      | otherwise = waver (n - 1) (acc + wave (A.constant (fromIntegral n) * A.the phi) x)

    wrap n
      = let n_  = A.truncate n :: Exp Int
            n'  = n - A.fromIntegral n_
        in
        (n_ `rem` 2 A./=* 0) A.? (1-n', n')


-- | Generate the value for a single wave.
waves degree phi x = wrap $ waver degree 0
  where
    waver :: Int -> Exp Float -> Exp Float
    waver n acc
      | n == 0    = acc
      | otherwise = waver (n - 1) (acc + wave (A.constant (fromIntegral n) * A.the phi) x)

    wrap n
      = let n_  = A.truncate n :: Exp Int
            n'  = n - A.fromIntegral n_
        in
        (n_ `rem` 2 A./=* 0) A.? (1-n', n')


-- | Generate the value for a single wave.