# include "pswarp.h"

void pswarpTransformTileArgsFree (pswarpTransformTileArgs *args) {
    if (!args) return;
    return;
}

pswarpTransformTileArgs *pswarpTransformTileArgsAlloc() {

    pswarpTransformTileArgs *args = (pswarpTransformTileArgs *)psAlloc(sizeof(pswarpTransformTileArgs));
    psMemSetDeallocator(args, (psFreeFunc)pswarpTransformTileArgsFree);

    args->input = NULL;
    args->output = NULL;
    args->grid = NULL;
    args->interp = NULL;
    args->region = NULL;

    args->gridX = 0;
    args->gridY = 0;

    args->goodPixels = 0;

    return args;
}

bool pswarpTransformTile (pswarpTransformTileArgs *args) {

    // int inCol0 = args->input->image->col0;
    // int inRow0 = args->input->image->row0;
    int inNcol = args->input->image->numCols;
    int inNrow = args->input->image->numRows;

    int outCol0 = args->output->image->col0;
    int outRow0 = args->output->image->row0;
    // int outNcol = args->output->image->numCols;
    // int outNrow = args->output->image->numRows;

    // get the coordinate range for this grid tile
    psPlane minPt, maxPt;
    pswarpMapGridCoordRange (args->grid, args->gridX, args->gridY, &minPt, &maxPt);

    psF32 **outImageData     = (args->output->image)  ? args->output->image->data.F32  : NULL;
    psF32 **outVarData       = (args->output->weight) ? args->output->weight->data.F32 : NULL;
    psMaskType **outMaskData = (args->output->mask)   ? args->output->mask->data.U8    : NULL;

    pswarpMap *map = args->grid->maps[args->gridX][args->gridY];

    psImage *region = args->region;

    double xInRaw, yInRaw;

    // output values for this pixel
    double imageValue;
    double varValue;
    psMaskType maskValue;

    // Iterate over the output image pixels (parent frame)
    long goodPixels = 0;                // Number of input pixels landing on the output image
    for (int y = minPt.y; y < maxPt.y; y++) {
        for (int x = minPt.x; x < maxPt.x; x++) {

            // Only transform those pixels requested
            if (region && region->data.U8[y][x]) continue;

            // pswarpMapApply converts the output coordinate (x,y) to the input coordinate.
            // both are in the parent frames of the input and output images.
            pswarpMapApply (&xInRaw, &yInRaw, map, x + 0.5, y + 0.5);

            double xIn = xInRaw - outCol0;	// Position on input image
	    double yIn = yInRaw - outRow0;	// Position on input image

            if (xIn < 0) continue;
            if (yIn >= inNcol) continue;
            if (yIn < 0) continue;
            if (yIn >= inNrow) continue;

            goodPixels++;

            // psImagePixelInterpolate determines the value at pixel coordinate (x,y) in child coordinates
            if (!psImageInterpolate(&imageValue, &varValue, &maskValue, xIn, yIn, args->interp)) {
                psError(PS_ERR_UNKNOWN, false, "Unable to interpolate image.");
                return false;
            }

            int xOut = x - outCol0;     // Position on output image
	    int yOut = y - outRow0;	// Position on output image

	    // not all images need be transformed
	    if (outImageData) {
		outImageData[yOut][xOut] = imageValue;
	    }
            if (outVarData) {
                outVarData[yOut][xOut] = varValue;
            }
            if (outMaskData) {
                outMaskData[yOut][xOut] = maskValue;
            }
        }
    }
    args->goodPixels = goodPixels;
    return true;
}
