/* @(#) 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 <vips/intl.h>

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

#include <vips/vips.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);
}
