#ifndef PASTELGFX_DRAW_TEXTURED_BOX_HPP
#define PASTELGFX_DRAW_TEXTURED_BOX_HPP
#include "pastel/gfx/drawing/draw_textured_box.h"
#include "pastel/gfx/color/colormixer/assign_colormixer.h"
#include "pastel/math/matrix/matrix.h"
#include "pastel/sys/intersect_alignedbox_alignedbox.h"
#include "pastel/sys/syscommon.h"
namespace Pastel
{
    template <
        typename Image_Element,
        typename Image_View,
        typename ColorMixer>
    void drawTexturedBox(
        const AlignedBox2& box,
        const Texture<Image_Element>& textureSampler,
        const View<2, Image_Element, Image_View>& image,
        const AlignedBox2& textureBox,
        const ColorMixer& colorMixer)
    {
        Vector2 delta = box.extent();
        AlignedBox2i discreteBox(
            toPixelSpanPoint(box.min()), 
            toPixelSpanPoint(box.max()));
        AlignedBox2i window(
            Vector2i(0), 
            image.extent());
        AlignedBox2i clippedBox;
        if (!intersect(discreteBox, window, clippedBox))
        {
            return;
        }
        Vector2 textureDelta = textureBox.extent();
        Vector2 duvDxy = textureDelta / delta;
        Vector2 uvMin = textureBox.min() + 
            ((Vector2(discreteBox.min()) + 0.5) - box.min()) * duvDxy;
        Vector2 uv(uvMin);
        Vector2 duvDx(duvDxy.x(), 0);
        Vector2 duvDy(0, duvDxy.y());
        using Cursor = typename Image_View::Cursor;
        Cursor yCursor = image.cursor(clippedBox.min());
        integer width = clippedBox.extent()[0];
        integer height = clippedBox.extent()[1];
        for (integer y = 0; y < height;++y)
        {
            Cursor xyCursor = yCursor;
            uv.x() = uvMin.x();
            for (integer x = 0; x < width;++x)
            {
                *xyCursor = colorMixer(*xyCursor,
                    textureSampler(uv, matrix2x2<dreal>(duvDx, duvDy)));
                uv.x() += duvDxy.x();
                xyCursor.xIncrement();
            }
            uv.y() += duvDxy.y();
            yCursor.yIncrement();
        }
    }
    template <
        typename Image_Element,
        typename Image_View>
    void drawTexturedBox(
        const AlignedBox2& box,
        const Texture<Image_Element>& textureSampler,
        const View<2, Image_Element, Image_View>& image,
        const AlignedBox2& textureBox)
    {
        drawTexturedBox(box, textureSampler, image, 
            textureBox, assignColorMixer<Image_Element>());
    }
    template <
        typename Image_Element,
        typename Image_View>
    void drawTexturedBox(
        const AlignedBox2& box,
        const Texture<Image_Element>& textureSampler,
        const View<2, Image_Element, Image_View>& image)
    {
        drawTexturedBox(box, textureSampler, 
            image, AlignedBox2(0, 0, 1, 1));
    }
}
#endif