#include <amscppimglib4/amscppimglib4.hpp>
#include <amscppimglib4/amscppimglib4_intlutil.hpp>

namespace ams
{
namespace imglib4
{

    void amsimage_region_copy_tf(
        int threadnum,
        int nthreads,
        uint8_t *datato,
        int Nxto,
        int Nyto,
        const uint8_t *datafrom,
        int Nxfrom,
        int Nyfrom,
        int offsetx,
        int offsety
    )
    {
        int64_t I,I0,I1,Is,N,Ix,Iy;
        int dx,dy;

        dx = Nxfrom;
        dx = (dx>(Nxto-offsetx)) ? (Nxto-offsetx) : dx;
        dx = (dx<0) ? 0 : dx;

        dy = Nyfrom;
        dy = (dy>(Nyto-offsety)) ? (Nyto-offsety) : dy;
        dy = (dy<0) ? 0 : dy;

        N = dx*dy;

        Is = N/nthreads;
        I0 = (threadnum)*Is;
        I1 = (threadnum<nthreads-1) ? (threadnum+1)*Is : N;

        for(I=I0;I<I1;I++)
        {
            Ix = I%dx;
            Iy = I/dx;

            datato[0 + 4*(Ix+offsetx) + 4*Nxto*(Iy+offsety)] = 
            datafrom[0 + 4*Ix + 4*Nxfrom*Iy];

            datato[1 + 4*(Ix+offsetx) + 4*Nxto*(Iy+offsety)] = 
            datafrom[1 + 4*Ix + 4*Nxfrom*Iy];
            
            datato[2 + 4*(Ix+offsetx) + 4*Nxto*(Iy+offsety)] = 
            datafrom[2 + 4*Ix + 4*Nxfrom*Iy];
            
            datato[3 + 4*(Ix+offsetx) + 4*Nxto*(Iy+offsety)] = 
            datafrom[3 + 4*Ix + 4*Nxfrom*Iy];
        }

        return;
    }

    void amsimage_region_copy(
        uint8_t *datato,
        int Nxto,
        int Nyto,
        const uint8_t *datafrom,
        int Nxfrom,
        int Nyfrom,
        int offsetx,
        int offsety
    )
    {
        int dx,dy;
        int64_t N;

        if(datato==NULL) return;
        if(datafrom==NULL) return;

        dx = Nxfrom;
        dx = (dx>(Nxto-offsetx)) ? (Nxto-offsetx) : dx;
        dx = (dx<0) ? 0 : dx;

        dy = Nyfrom;
        dy = (dy>(Nyto-offsety)) ? (Nyto-offsety) : dy;
        dy = (dy<0) ? 0 : dy;

        N = dx*dy;

        threaded_execute(
            amsimage_region_copy_tf,
            N,
            datato,
            Nxto,Nyto,
            datafrom,
            Nxfrom,Nyfrom,
            offsetx,offsety
        );


        return;
    }
    
    void amsimage_region_set_tf(
        int threadnum,
        int nthreads,
        uint8_t *data,
        int Nx, int Ny,
        int x0, int y0,
        int x1, int y1,
        amspixel val
    )
    {
        int64_t I,I0,I1,Is,N,Ix,Iy;
        int dx,dy;

        dx = (x1-x0); dy = (y1-y0);
        dx = (dx<0) ? 0 : dx;
        dy = (dy<0) ? 0 : dy;
        N = dx*dy;

        Is = N/nthreads;
        I0 = (threadnum)*Is;
        I1 = (threadnum<nthreads-1) ? (threadnum+1)*Is : N;

        for(I=I0;I<I1;I++)
        {
            Ix = I%dx;
            Iy = I/dx;

            data[0 + 4*(Ix+x0) + 4*Nx*(Iy+y0)] = val.R;
            data[1 + 4*(Ix+x0) + 4*Nx*(Iy+y0)] = val.G;
            data[2 + 4*(Ix+x0) + 4*Nx*(Iy+y0)] = val.B;
            data[3 + 4*(Ix+x0) + 4*Nx*(Iy+y0)] = val.A;
        }

        return;
    }

    void amsimage_region_set(
        uint8_t *data,
        int Nx, int Ny,
        int x0, int y0,
        int x1, int y1,
        amspixel val
    )
    {
        int dx,dy;
        int64_t N;

        if(data==NULL) return;

        dx = (x1-x0); dy = (y1-y0);
        dx = (dx<0) ? 0 : dx;
        dy = (dy<0) ? 0 : dy;
        N = dx*dy;

        threaded_execute(
            amsimage_region_set_tf,
            N,
            data, Nx,Ny, 
            x0, y0, x1, y1, 
            val
        );

        return;
    }



}; //end namespace imglib4
}; //end namespace ams