module Data.MovingAverage.DoubleExponential
    ( doubleExponential
    ) where

import Data.MovingAverage.Types (SmoothedResults, MovingAverageError(..), buildDoubleExponentialMovingAverage)

doubleExponential :: (Ord a, Floating a) => a -> a -> [a] -> Either MovingAverageError (SmoothedResults a)
doubleExponential _ _ [] = Left NoValuesProvided
doubleExponential alpha beta xs =
    case (inRange 0 1 alpha, inRange 0 1 beta) of
        (True, True) -> Right $ processResults $ scanl go initialState (tail xs)
        (False, _) -> Left $ InvalidAlphaValue "Alpha must be 0 < a < 1"
        (_, False) -> Left $ InvalidBetaValue "Beta must be 0 < b < 1"
  where
    processResults = buildDoubleExponentialMovingAverage alpha beta . map pairFromTriple
    go (_, sPrevious, betaPrevious) current =
        ( current
        , s_t current sPrevious betaPrevious
        , b_t (s_t current sPrevious betaPrevious) sPrevious betaPrevious
        )
    initialState = (head xs, head xs, xs !! 1 - head xs)
    s_t y sPrevious betaPrevious = alpha * y + (1 - alpha) * (sPrevious + betaPrevious)
    b_t sCurrent sPrevious betaPrevious = beta * (sCurrent - sPrevious) + (1 - beta) * betaPrevious

inRange :: Ord a => a -> a -> a -> Bool
inRange min' max' value = value > min' && value < max'

pairFromTriple :: (a, b, c) -> (a, b)
pairFromTriple (a, b, _) = (a, b)