/*
 * 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_MULTI_H
#define ECXX_CTL_GFX_COLOR_ANIMATION_1D_PROC_BLINK_MULTI_H


namespace eCxx {


//
// A simple 1-dimensional animation processor class - blink between multiple colors
//
template <
    typename ColorAnimator1D_T,
    uint8_t  ColorArraySizeN,
    typename AnimProcColorT = typename ColorAnimator1D_T::ColorFX1DType::BufferColorType
>
class Animation1DProc_BlinkMulti : 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;

        static constexpr uint8_t ColorArrayElementCount = ColorArraySizeN;

    public:
        template <
            typename... ColorTs,
            typename    IsAllSame = typename eCxx::isAllSame<AnimProcColorType, ColorTs...>::Type
        >
        inline Animation1DProc_BlinkMulti(const ColorTs&... colors);

        inline virtual ~Animation1DProc_BlinkMulti();

        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
        //        index
        inline void set(uint8_t index);

#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 _colors[ColorArrayElementCount];

              uint8_t           _index;
};


template <typename ColorAnimator1D_T, uint8_t ColorArraySizeN, typename AnimProcColorT> template <typename... ColorTs, typename IsAllSame>
inline Animation1DProc_BlinkMulti<ColorAnimator1D_T, ColorArraySizeN, AnimProcColorT>
::Animation1DProc_BlinkMulti(const ColorTs&... colors)
: _colors  { colors... }
, _index   ( 0         )
{}


template <typename ColorAnimator1D_T, uint8_t ColorArraySizeN, typename AnimProcColorT>
inline Animation1DProc_BlinkMulti<ColorAnimator1D_T, ColorArraySizeN, AnimProcColorT>
::~Animation1DProc_BlinkMulti()
{}


template <typename ColorAnimator1D_T, uint8_t ColorArraySizeN, typename AnimProcColorT>
void Animation1DProc_BlinkMulti<ColorAnimator1D_T, ColorArraySizeN, AnimProcColorT>
::reset(ColorFX1DType&, BufferSizeType, BufferSizeType)
{ _index = 0; }


template <typename ColorAnimator1D_T, uint8_t ColorArraySizeN, typename AnimProcColorT>
void Animation1DProc_BlinkMulti<ColorAnimator1D_T, ColorArraySizeN, AnimProcColorT>
::update(ColorFX1DType& colorFX1D, BufferSizeType elemBeginIdx, BufferSizeType elemEndIdx)
{
    // Determine the current color
    const typename ColorFX1DType::BufferColorType& color = _colors[_index];

    // Update the index
    if(++_index >= ColorArrayElementCount) _index = 0;

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


template <typename ColorAnimator1D_T, uint8_t ColorArraySizeN, typename AnimProcColorT>
inline void Animation1DProc_BlinkMulti<ColorAnimator1D_T, ColorArraySizeN, AnimProcColorT>
::set(uint8_t index)
{ _index = (index < ColorArrayElementCount) ? index : (ColorArrayElementCount - 1); }


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

template <typename ColorAnimator1D_T, uint8_t ColorArraySizeN, typename AnimProcColorT>
CBP::QUInt Animation1DProc_BlinkMulti<ColorAnimator1D_T, ColorArraySizeN, AnimProcColorT>
::estimatedTotalAnimationFrameCount() const
{ return ColorArrayElementCount; }

#endif


} // namespace eCxx


#endif
