/* @(#) Function which changes the spatial resolution of an image according to
 * @(#) step
 * @(#)
 * @(#) int im_spatres(in, out, step)
 * @(#) IMAGE *in, *out;
 * @(#) int step;
 * @(#) Returns either 0 (sucess) or -1 (fail)
 * @(#)
 * @(#) Picture can have any number of channels (max 64).
 *
 * Copyright: 1990, N. Dessipris.
 *
 * Author: Nicos Dessipris
 * Written on: 08/11/1989.
 * Modified on: 19/01/1990.
 */

/*

	This file is part of VIPS.

	VIPS is free software; you can redistribute it and/or modify
	it under the terms of the GNU Lesser General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public License
	along with this program; if not, write to the Free Software
	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
	02110-1301  USA

 */

/*

	These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk

 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /*HAVE_CONFIG_H*/
#include <glib/gi18n-lib.h>

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#include <vips/vips.h>
#include <vips/vips7compat.h>

int
im_spatres(IMAGE *in, IMAGE *out, int step)
{
	int x, y; /* horizontal and vertical direction */
	int z;	  /* 0 <= z < channel	*/
	int i, j;
	int rounding, step2, sum;
	unsigned char *values;
	unsigned char *input, *cpinput, *cp2input, *line, *cpline, *pnt, *cpnt;
	int os;

	/* Check args */
	if (step < 1) {
		im_error("im_spatres", _("Invalid step %d"), step);
		return -1;
	}

	if ((in->Xsize / step == 0) || (in->Ysize / step == 0)) {
		im_error("im_spatres", _("Invalid step %d"), step);
		return -1;
	}

	if (im_iocheck(in, out) == -1)
		return -1;

	if ((in->Coding != IM_CODING_NONE) || (in->BandFmt != IM_BANDFMT_UCHAR)) {
		im_error("im_spatres", "%s", _("wrong input"));
		return -1;
	}

	/* Prepare output */
	if (im_cp_desc(out, in) == -1)
		return -1;
	out->Xsize = in->Xsize - in->Xsize % step;
	out->Ysize = in->Ysize - in->Ysize % step;

	if (im_setupout(out) == -1)
		return -1;

	/* Malloc buffer for one 'line' of input data */
	os = in->Xsize * in->Bands;
	line = (unsigned char *) calloc((unsigned) os, sizeof(char));
	/* Malloc space for values */
	values = (unsigned char *) calloc((unsigned) out->Bands, sizeof(char));
	if (line == NULL || values == NULL) {
		im_error("im_spatres", "%s", _("calloc failed"));
		return -1;
	}

	step2 = step * step;
	rounding = step2 / 2;
	input = (unsigned char *) in->data;
	for (y = 0; y < out->Ysize; y += step) {
		cpinput = input;
		input += os * step;
		/* do the x loop out->Xsize / step times */
		cpline = line;
		for (x = 0; x < out->Xsize; x += step) {
			cp2input = cpinput;
			cpinput += step * out->Bands; /* ??? */
			for (z = 0; z < out->Bands; z++) {
				pnt = cp2input + z;
				sum = 0;
				for (j = 0; j < step; j++) {
					cpnt = pnt;
					pnt += os;
					for (i = 0; i < step; i++) {
						sum += (int) *cpnt;
						cpnt += out->Bands;
					}
				}
				*(values + z) = (PEL) ((sum + rounding) / step2);
			}
			/* for this x, write step*bands data  */
			for (j = 0; j < step; j++)
				for (z = 0; z < out->Bands; z++)
					*cpline++ = *(values + z);
		}
		/* line is now ready. Write now step lines */
		for (j = 0; j < step; j++)
			if (im_writeline(y + j, out, (PEL *) line) == -1) {
				free((char *) line);
				free((char *) values);
				return -1;
			}
	} /* end of the for (..y..) loop */

	free((char *) line);
	free((char *) values);
	return 0;
}
