


import java.util.*;

/**
 *
 * @author  Jacek Ruminski
 */
public class Convolution {
    
    public static final int NO_EDGE=0;
    public static final int PERIODICAL=1;
    public static final int SYMMETRIC=2;
    
    
    /** Creates a new instance of Convolution */
    public Convolution() {
    }
    
    public double [] convolve1D(double data[],double filter[], int edgeCondition, boolean normalize){
        int edge=filter.length/2;
        double result[] = new double[data.length];
        int size=data.length;
        int filterLength=filter.length;
        int reducedSize=size-edge;
        int middle=edge+1;
        if ((filterLength%2)==0){
            System.out.println("ERROR: Only odd length filters are accepted");
            return null;
        }
        double tempValue=0;
        double normalization=0;
        for(int i=0; i<filterLength; i++){
            normalization+=filter[i];
        }
        if (normalization==0)
            normalization=1;
                
        for(int i=0; i<(size-filterLength+1); i++){
            tempValue=0;
            for(int j=0; j<filterLength; j++){
                tempValue+=data[i+j]*filter[j];
            }
            if (normalize) tempValue/=normalization;
            result[i+edge]=tempValue;
        }
        
        double edgeData[] = new double[filterLength];
        
        boolean noOpFlag=false;
        //LEFT SIDE
        for(int j=0; j<edge; j++){
            switch(edgeCondition){
                case PERIODICAL:    
                                    for(int i=0; i<(edge-j);i++){
                                       edgeData[i]=data[size-edge+i+j]; 
                                    }
                                    for(int i=(edge-j),k=0; i<filterLength;i++,k++){
                                       edgeData[i]=data[k]; 
                                    }
                                    break;
                case SYMMETRIC:    
                                    for(int i=0; i<(edge-j);i++){
                                       edgeData[i]=data[i+1]; 
                                    }
                                    for(int i=(edge-j),k=0; i<filterLength;i++,k++){
                                       edgeData[i]=data[k]; 
                                    }
                                    break;
                default:            noOpFlag=true;     
            }//end of switch
            //convolve
            if(!noOpFlag){
                tempValue=0;
                for(int i=0; i<filterLength; i++){
                    tempValue+=edgeData[i]*filter[i];
                }
                if (normalize) tempValue/=normalization;
                result[j]=tempValue;
            } else{
                result[j]=data[j];
            }
            
        }//end of for j   
        
        //RIGHT SIDE
        for(int j=0; j<edge; j++){
            switch(edgeCondition){
                case PERIODICAL:    
                                    for(int i=((size-1)-edge-j),l=0; i<size;i++,l++){
                                       edgeData[l]=data[i]; 
                                    }
                                    
                                    for(int i=(edge+1+j),k=0; i<filterLength;i++,k++){
                                       edgeData[i]=data[k]; 
                                    }
                                    break;
                case SYMMETRIC:    
                                    for(int i=((size-1)-edge-j),l=0; i<size;i++,l++){
                                       edgeData[l]=data[i]; 
                                    }
                                    
                                    for(int i=(edge+1+j),k=2; i<filterLength;i++,k++){
                                       edgeData[i]=data[size-k]; 
                                    }
                                    break;
                default:            noOpFlag=true;     
            }//end of switch
            //convolve
            if(!noOpFlag){
                tempValue=0;
                for(int i=0; i<filterLength; i++){
                    tempValue+=edgeData[i]*filter[i];
                }
                if (normalize) tempValue/=normalization;
                result[size-1-j]=tempValue;
            } else{
                result[size-1-j]=data[size-1-j];
            }
            
        }//end of for j   
        return result;
    }//end of double [] convolve1D
    
    
    
    public static void main(String a[]){
        
        Convolution con = new Convolution();
        //double data[] = {10, 20,30,20,10,20,30,20,10,20,30};
        double data[] = {100, 100,100,100,200,200,200,200};
        double filter[] = {-1.0/8.0,2.0/8.0,6.0/8.0,2.0/8.0,-1.0/8.0};
        System.out.println("Wymiar:" +filter.length);
        //double filter[] = {1.0/5.0,1.0/5.0,1.0/5.0,1.0/5.0,1.0/5.0};
        
        System.out.println(Arrays.toString(data));
        System.out.println(Arrays.toString(filter));
        System.out.println(Arrays.toString(con.convolve1D(data,filter,Convolution.SYMMETRIC, true)));
    }
    
    
    
    
}
