/*
 * Copyright (C) 2020-2021 Aloysius Indrayanto
 *
 * This file is part of the eCxx library, see LICENSE file for the license details.
 */


#ifndef ECXX_CTL_GFX_COLOR_ANIMATION_1D_PROC_BLINK_H
#define ECXX_CTL_GFX_COLOR_ANIMATION_1D_PROC_BLINK_H


namespace eCxx {


//
// A simple 1-dimensional animation processor class - blink between off and on colors
//
template <
    typename ColorAnimator1D_T,
    typename AnimProcColorT = typename ColorAnimator1D_T::ColorFX1DType::BufferColorType
>
class Animation1DProc_Blink : public ColorAnimator1D_T::Animation1DProcType {
    public:
        using AnimProcColorType   = AnimProcColorT;
        using ColorAnimator1DType = ColorAnimator1D_T;
        using ColorFX1DType       = typename ColorAnimator1D_T::Animation1DProcType::ColorFX1DType;
        using BufferColorType     = typename ColorAnimator1D_T::Animation1DProcType::BufferColorType;
        using BufferSizeType      = typename ColorAnimator1D_T::Animation1DProcType::BufferSizeType;

    public:
        inline Animation1DProc_Blink(const AnimProcColorType& colorOff, const AnimProcColorType& colorOn);
        inline virtual ~Animation1DProc_Blink();

        virtual void reset(ColorFX1DType& colorFX1D, BufferSizeType elemBeginIdx, BufferSizeType elemEndIdx);
        virtual void update(ColorFX1DType& colorFX1D, BufferSizeType elemBeginIdx, BufferSizeType elemEndIdx);

        // NOTE : Can be called manually anytime after reset() to change the current
        //        state
        inline void set(bool state);

#if defined(__x86_64__) || defined(__i386__)
        // NOTE : This animation processor implementation does not require reset() to be
        //        called first for this function to work properly
        virtual CBP::QUInt estimatedTotalAnimationFrameCount() const;
#endif

    private:
        const AnimProcColorType _colorOff;
        const AnimProcColorType _colorOn;

              bool              _state;
};


template <typename ColorAnimator1D_T, typename AnimProcColorT>
inline Animation1DProc_Blink<ColorAnimator1D_T, AnimProcColorT>
::Animation1DProc_Blink(const AnimProcColorType& colorOff, const AnimProcColorType& colorOn)
: _colorOff(colorOff)
, _colorOn (colorOn )
, _state   (false   )
{}


template <typename ColorAnimator1D_T, typename AnimProcColorT>
inline Animation1DProc_Blink<ColorAnimator1D_T, AnimProcColorT>
::~Animation1DProc_Blink()
{}


template <typename ColorAnimator1D_T, typename AnimProcColorT>
void Animation1DProc_Blink<ColorAnimator1D_T, AnimProcColorT>
::reset(ColorFX1DType&, BufferSizeType, BufferSizeType)
{ _state = false; }


template <typename ColorAnimator1D_T, typename AnimProcColorT>
void Animation1DProc_Blink<ColorAnimator1D_T, AnimProcColorT>
::update(ColorFX1DType& colorFX1D, BufferSizeType elemBeginIdx, BufferSizeType elemEndIdx)
{
    // Determine the current color
    const typename ColorFX1DType::BufferColorType& color = _state ? _colorOn : _colorOff;

    // Invert the state
    _state = !_state;

    // Set the color(s)
    for(BufferSizeType i = elemBeginIdx; i <= elemEndIdx; ++i) {
        colorFX1D.set(i, color);
    }
}


template <typename ColorAnimator1D_T, typename AnimProcColorT>
inline void Animation1DProc_Blink<ColorAnimator1D_T, AnimProcColorT>
::set(bool state)
{ _state = state; }


#if defined(__x86_64__) || defined(__i386__)

template <typename ColorAnimator1D_T, typename AnimProcColorT>
CBP::QUInt Animation1DProc_Blink<ColorAnimator1D_T, AnimProcColorT>
::estimatedTotalAnimationFrameCount() const
{ return 2; }

#endif


} // namespace eCxx


#endif
