/*
 * 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_XPOLICY_H
#define ECXX_CTL_GFX_COLOR_XPOLICY_H


namespace eCxx {


//
// Color policy structures for various addressable digital LEDs
//
struct APA102XPolicy : public Uninstantiable {
    static constexpr uint8_t _()
    { return 0b11100000 | 0b00011111; }

    static constexpr uint8_t _(uint8_t, uint8_t, uint8_t)
    { return _(); }

    static constexpr uint8_t _(uint8_t globalBrightness5, uint8_t, uint8_t, uint8_t)
    { return 0b11100000 | (globalBrightness5 & 0b00011111); }

    static inline void preXPolicy(uint8_t& x, uint8_t, uint8_t, uint8_t)
    { x = (x & 0b00011111) << 3; }

    static inline void postXPolicy(uint8_t& x, uint8_t, uint8_t, uint8_t)
    { x = _(x >> 3, 0, 0, 0); }
};

using SK9822XPolicy = APA102XPolicy;


struct P9813BGRXPolicy : public Uninstantiable {
    static constexpr uint8_t _()
    { return 0b11000000 | 0b00111111; }

    static constexpr uint8_t _(uint8_t r, uint8_t g, uint8_t b)
    { return 0b11000000 | ( (~b & 0b11000000) >> 2 ) | ( (~g & 0b11000000) >> 4 ) | ( (~r & 0b11000000) >> 6 ); }

    static constexpr uint8_t _(uint8_t, uint8_t r, uint8_t g, uint8_t b)
    { return _(r, g, b); }

    static inline void preXPolicy(uint8_t, uint8_t, uint8_t, uint8_t)
    {}

    static inline void postXPolicy(uint8_t& x, uint8_t r, uint8_t g, uint8_t b)
    { x = _(r, g, b); }
};


//
// A helper structure to check if the color type is a match
//
template <typename XPolicyT>
struct XBGRColor;

template < template <typename> class XRGBColorT >
struct MatchP9813BGRColorType : public Uninstantiable {
    static_assert(
        eCxx::isSame< XRGBColorT<P9813BGRXPolicy>, XBGRColor<P9813BGRXPolicy> >::Value,
        "template argument substituting XRGBColorT is not an XBGRColor<T>"
    );

    using ColorType = XBGRColor<P9813BGRXPolicy>;
};


} // namespace eCxx


#endif
