/*******************************************************************************
 * Copyright (c) 2010 Attila Kovacs <attila_kovacs@post.harvard.edu>.
 * All rights reserved. 
 * 
 * This file is part of crush.
 * 
 *     crush is free software: you can redistribute it and/or modify
 *     it under the terms of the GNU General Public License as published by
 *     the Free Software Foundation, either version 3 of the License, or
 *     (at your option) any later version.
 * 
 *     crush 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 General Public License for more details.
 * 
 *     You should have received a copy of the GNU General Public License
 *     along with crush.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * Contributors:
 *     Attila Kovacs <attila_kovacs@post.harvard.edu> - initial API and implementation
 ******************************************************************************/
// Copyright (c) 2007 Attila Kovacs 

package util;

public final class ArrayExtras {

    public static double[] stretch(double[] data, int n) {
	double[] stretched = new double[data.length * n];
	for(int i=0; i<data.length; i++) stretched[n*i] = data[i];
	return stretched;
    }

    public static double[] shrink(double[] data, int n) {
	double[] shrunk = new double[data.length/n];
	for(int i=0; i<shrunk.length; i++) shrunk[i] = data[n*i];
	return shrunk;
    }

    public static double[] boxcar(double[] data, int n) {
	double[] smoothed = new double[data.length];
	double sum = 0.0;
	int nans = 0;

	for(int i=0; i<n; i++) {
	    if(Double.isNaN(data[i])) nans++;
	    else sum += data[i];
	}

	for(int i=n,j=0; i<data.length; i++,j++) {	  
	    smoothed[j] = nans > 0 ? Double.NaN : sum;

	    if(Double.isNaN(data[i])) nans++;
	    else sum += data[i];

	    if(Double.isNaN(data[j])) nans--;
	    else sum -= data[j];
	}
	smoothed[data.length-n] = sum;

	for(int i=data.length-n+1; i<data.length; i++) smoothed[i] = Double.NaN;
	
	return smoothed;
    }

    public static double[] shift(double[] data, int n) {
	if(n>0) {
	    for(int to=data.length-1, from=to-n; from > 0; to--, from--)
		data[to] = data[from];
	    for(int i=0; i<n; i++) data[i] = Double.NaN;
	}
	else {
	    for(int to=0, from=n; from < data.length; to++, from++)
		data[to] = data[from];
	    for(int i=data.length-1-n; i<data.length; i++) data[i] = Double.NaN;
	}
	
	return data;
    }


    public static double[] shift(double[] data, double d, double accuracy) {
	int n = (int) Math.round(1.0/accuracy);
	int dN = (int) Math.round(d/accuracy);
	return shrink(shift(boxcar(stretch(data, n), n), dN), n);
    }

}
