/*
 * 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_FX_2D_PAINTER_H
#define ECXX_CTL_GFX_COLOR_FX_2D_PAINTER_H


#include "BitmapFont.h"
#include "ColorFX2D.h"


namespace eCxx {


//
// Helper structure for ColorFX2DPainter<T>
//
template <typename ColorFX2DPainter_T, typename BufferT, CBP::SUInt XSizeN, CBP::SUInt YSizeN, typename LayoutPolicyT, typename BufferPolicyT, CBP::SUInt BlockXSizeN, CBP::SUInt BlockYSizeN>
struct ColorFX2DPainter_CMHelper;


//
// A simple ColorFX2D<T> based painter
//
// # Template argument ColorPGMPtrT is used when reading color data from program memory, it must
//   be one of PGMCharPointer and PGMCharPointerFar.
//
template <
    typename   BufferColorT,
    CBP::SUInt XSizeN,
    CBP::SUInt YSizeN,
    typename   LayoutPolicyT        = CBP::DefaultLayout,
    typename   BufferPolicyT        = CBP::EncapsulatedBuffer,
    CBP::SUInt BlockXSizeN          = 0,
    CBP::SUInt BlockYSizeN          = 0,
    CBP::SUInt InterYSizeN          = 0,
    bool       UseDoubleBufferring_ = false,
    typename   ColorPGMPtrT         = PGMCharPointer
>
class ColorFX2DPainter : public ColorFX2D<BufferColorT, XSizeN, YSizeN, LayoutPolicyT, BufferPolicyT, BlockXSizeN, BlockYSizeN, InterYSizeN, UseDoubleBufferring_, ColorPGMPtrT> {
    private:
        using _CFX2D = ColorFX2D<BufferColorT, XSizeN, YSizeN, LayoutPolicyT, BufferPolicyT, BlockXSizeN, BlockYSizeN, InterYSizeN, UseDoubleBufferring_, ColorPGMPtrT>;

    public:
        using ColorPGMPointerType = typename _CFX2D::ColorPGMPointerType;
        using BufferPolicyType    = typename _CFX2D::BufferPolicyType;
        using LayoutPolicyType    = typename _CFX2D::LayoutPolicyType;

        using BufferColorType     = typename _CFX2D::BufferColorType;
        using BufferSizeType      = typename _CFX2D::BufferSizeType;
        using BufferByteSizeType  = typename _CFX2D::BufferByteSizeType;

        using BufferArrayType     = typename _CFX2D::BufferArrayType;
        using Iterator            = typename _CFX2D::Iterator;
        using ConstIterator       = typename _CFX2D::ConstIterator;

        static constexpr CBP::SUInt         BlockXSize          = _CFX2D::BlockXSize;
        static constexpr CBP::SUInt         BlockYSize          = _CFX2D::BlockYSize;
        static constexpr CBP::SUInt         InterYSize          = _CFX2D::InterYSize;

        static constexpr CBP::SUInt         XElementCount       = _CFX2D::XElementCount;
        static constexpr CBP::SUInt         YElementCount       = _CFX2D::YElementCount;

        static constexpr uint8_t            ColorByteSize       = _CFX2D::ColorByteSize;
        static constexpr BufferSizeType     BufferElementCount  = _CFX2D::BufferElementCount;
        static constexpr BufferByteSizeType BufferByteSize      = _CFX2D::BufferByteSize;

        static constexpr bool               UseDoubleBufferring = _CFX2D::UseDoubleBufferring;

    private:
        using _CMHelper = ColorFX2DPainter_CMHelper<ColorFX2DPainter, BufferArrayType, XElementCount, YElementCount, LayoutPolicyType, BufferPolicyType, BlockXSize, BlockYSize>;

    public:
        inline ColorFX2DPainter() = default;
        inline ~ColorFX2DPainter() = default;

        inline ColorFX2DPainter(const ColorFX2DPainter&) = default;
        inline ColorFX2DPainter(ColorFX2DPainter&&) = delete;

        inline ColorFX2DPainter& operator=(const ColorFX2DPainter&) = default;
        inline ColorFX2DPainter& operator=(ColorFX2DPainter&&) = delete;

    public:
        // Put one character
        template <typename ColorT, typename FontPGMPointerT>
        inline void putCharXY(CBP::DSInt x, CBP::DSInt y, const ColorT& color, char ch, const BitmapFont<FontPGMPointerT>& font);

        // Put text - flow horizontally
        template <typename ColorT, typename FontPGMPointerT>
        inline void putHTextXY(CBP::DSInt x, CBP::DSInt y, const ColorT& color, const char* text, const BitmapFont<FontPGMPointerT>& font, CBP::SSInt nextCharOffset = 0);

        template <typename ColorT, typename TextPGMPointerT, typename FontPGMPointerT>
        inline void putHTextXY(CBP::DSInt x, CBP::DSInt y, const ColorT& color, TextPGMPointerT text, const BitmapFont<FontPGMPointerT>& font, CBP::SSInt nextCharOffset = 0);

        template <typename ColorT, typename FontPGMPointerT>
        inline void putRevHTextXY(CBP::DSInt x, CBP::DSInt y, const ColorT& color, const char* text, const BitmapFont<FontPGMPointerT>& font, CBP::SSInt nextCharOffset = 0);

        template <typename ColorT, typename TextPGMPointerT, typename FontPGMPointerT>
        inline void putRevHTextXY(CBP::DSInt x, CBP::DSInt y, const ColorT& color, TextPGMPointerT text, const BitmapFont<FontPGMPointerT>& font, CBP::SSInt nextCharOffset = 0);

        // Put text - flow vertically
        template <typename ColorT, typename FontPGMPointerT>
        inline void putVTextXY(CBP::DSInt x, CBP::DSInt y, const ColorT& color, const char* text, const BitmapFont<FontPGMPointerT>& font, CBP::SSInt nextCharOffset = 0);

        template <typename ColorT, typename TextPGMPointerT, typename FontPGMPointerT>
        inline void putVTextXY(CBP::DSInt x, CBP::DSInt y, const ColorT& color, TextPGMPointerT text, const BitmapFont<FontPGMPointerT>& font, CBP::SSInt nextCharOffset = 0);

        template <typename ColorT, typename FontPGMPointerT>
        inline void putRevVTextXY(CBP::DSInt x, CBP::DSInt y, const ColorT& color, const char* text, const BitmapFont<FontPGMPointerT>& font, CBP::SSInt nextCharOffset = 0);

        template <typename ColorT, typename TextPGMPointerT, typename FontPGMPointerT>
        inline void putRevVTextXY(CBP::DSInt x, CBP::DSInt y, const ColorT& color, TextPGMPointerT text, const BitmapFont<FontPGMPointerT>& font, CBP::SSInt nextCharOffset = 0);

        // Draw line
        template <typename ColorT>
        inline void drawHLine(CBP::DSInt x, CBP::DSInt y, CBP::DUInt size, const ColorT& color);

        template <typename ColorT>
        inline void drawVLine(CBP::DSInt x, CBP::DSInt y, CBP::DUInt size, const ColorT& color);

        template <typename ColorT>
        inline void drawGLine(CBP::DSInt x1, CBP::DSInt y1, CBP::DSInt x2, CBP::DSInt y2, const ColorT& color);

        // Draw rectangle
        template <typename ColorT>
        inline void drawRectangle(CBP::DSInt x1, CBP::DSInt y1, CBP::DSInt x2, CBP::DSInt y2, const ColorT& color);

        template <typename ColorT>
        inline void fillRectangle(CBP::DSInt x1, CBP::DSInt y1, CBP::DSInt x2, CBP::DSInt y2, const ColorT& color);

        // Draw circle
        template <typename ColorT>
        inline void drawCircle(CBP::DSInt xc, CBP::DSInt yc, CBP::DSInt r, const ColorT& color);

        template <typename ColorT>
        inline void fillCircle(CBP::DSInt xc, CBP::DSInt yc, CBP::DSInt r, const ColorT& color);

        // Draw ellipse
        template <typename ColorT>
        inline void drawEllipse(CBP::DSInt xc, CBP::DSInt yc, CBP::DSInt rx, CBP::DSInt ry, const ColorT& color);

        template <typename ColorT>
        inline void fillEllipse(CBP::DSInt xc, CBP::DSInt yc, CBP::DSInt rx, CBP::DSInt ry, const ColorT& color);

    private:
        // Put text - flow horizontally
        template <bool RevFlowDir, typename ColorT, typename FontPGMPointerT, typename TextPointerT>
        inline void _putGenHTextXY(CBP::DSInt x, CBP::DSInt y, const ColorT& color, TextPointerT text, const BitmapFont<FontPGMPointerT>& font, CBP::SSInt nextCharOffset);

        // Put text - flow vertically
        template <bool RevFlowDir, typename ColorT, typename FontPGMPointerT, typename TextPointerT>
        inline void _putGenVTextXY(CBP::DSInt x, CBP::DSInt y, const ColorT& color, TextPointerT text, const BitmapFont<FontPGMPointerT>& font, CBP::SSInt nextCharOffset);

        // Draw circle
        template <typename ColorT, bool Fill>
        inline void _dfCircle(CBP::DSInt xc, CBP::DSInt yc, CBP::DSInt r, const ColorT& color);

        // Draw ellipse
        template <typename ColorT, bool Fill>
        inline void _dfEllipse(CBP::DSInt xc, CBP::DSInt yc, CBP::DSInt rx, CBP::DSInt ry, const ColorT& color);
};


} // namespace eCxx


//
// Include the implementation file
//
#define INCLUDE_ECXX_CTL_GFX_COLOR_FX_2D_PAINTER_TPP
#include "ColorFX2DPainter.tpp"


#endif
