
import java.util.*;
/**
 *
 * @author  jwr
 */
public class WaveletFilters {

    public static final int DAUBECHIES_97 = 0;
    public static final int INTEGER_53 = 5;
    
    public double h0Filter[];
    public double h1Filter[];
    public double g0Filter[];
    public double g1Filter[];
    double indexes_h0 [];
    double indexes_h1 [];
    double indexes_g0 [];
    double indexes_g1 [];
    
    /*
     * Filtr Daubechies 9,7
     * h0 - low Pass 
     */
    public double h0Daubechies9[]={0.026748757410, -0.016864118442, -0.078223266528, 0.266864118441, 0.602949018236, 0.266864118441,-0.078223266528, -0.016864118442, 0.026748757410};
    
    /*
     * Filtr Daubechies 9,7
     * h1 - high Pass  
     */
    public double h1Daubechies7[]={0.091271763114, -0.057543526228, -0.591271763114, 1.115087052456, -0.591271763114, -0.057543526228,0.091271763114};
    
    public double h0Int5[]={-1.0/8.0,2.0/8.0,6.0/8.0,2.0/8.0,-1.0/8.0};
    public double h1Int3[]={-1.0/2.0,2.0/2.0,-1.0/2.0};
    
    
    public int currentFilter=-1;
    public double alpha=1;
    private boolean isAlpha=false;
    
    /** Creates a new instance of WaveletFilters */
    public WaveletFilters() {
    }
    
    public double [] getH0(int filterType){
        
        switch(filterType){
            case DAUBECHIES_97:
            default:
                                currentFilter=DAUBECHIES_97;
                                h0Filter=h0Daubechies9;
                                break;
            case INTEGER_53:
                                currentFilter=INTEGER_53;
                                h0Filter=h0Int5;
                                //h1=h1Int3;
                                break;
                                
            //default:
        }
        return h0Filter;
    }//end of 
    
    public double [] getH1(int filterType){
        
        switch(filterType){
            case DAUBECHIES_97:
            default:
                                currentFilter=DAUBECHIES_97;
                                h1Filter=h1Daubechies7;
                                break;
           case INTEGER_53:
                                currentFilter=INTEGER_53;
                                
                                h1Filter=h1Int3;
                                break;
                               
            //default:
        }
        return h1Filter;
    }//end of 
    
    public double [] getG0(int filterType){
        double [] g0;
        double [] h0;
        double [] h1;
        switch(filterType){
            case DAUBECHIES_97:
            default:
                                currentFilter=DAUBECHIES_97;
                                h0=h0Daubechies9;
                                h1=h1Daubechies7;
                                break;
            case INTEGER_53:
                                currentFilter=INTEGER_53;
                                h0=h0Int5;
                                h1=h1Int3;
                                break;
           
        }
        if(!isAlpha)
            alpha=calculateAlpha(h0, h1);
        g0=calculate_g0(alpha, h1);
        g0Filter=g0;
        return g0;
    }
    
    
    public double [] getG1(int filterType){
        double [] g1;
        double [] h0;
        double [] h1;
        switch(filterType){
            case DAUBECHIES_97:
            default:    
                                currentFilter=DAUBECHIES_97;
                                h0=h0Daubechies9;
                                h1=h1Daubechies7;
                                break;
            case INTEGER_53:
                                currentFilter=INTEGER_53;
                                h0=h0Int5;
                                h1=h1Int3;
                                break;
            
        }
        if(!isAlpha)
            alpha=calculateAlpha(h0, h1);
        g1=calculate_g1(alpha, h0);
        g1Filter=g1;
        return g1;
    }
    
    public double[] calculate_g0(double alpha, double [] h1){
        double [] g0;
        
        g0=new double[h1.length];
        int wym=g0.length-1;
        //alpha*-1,n*h1[-n]
        for(int i=0; i<=wym; i++){
            g0[i]=alpha*Math.pow(-1,indexes_h1[wym-i])*h1[wym-i];
            //System.out.println("Wynik H1, index, G0["+i+"]="+h1[wym-i]+", "+indexes_h1[wym-i]+", "+g0[i]);
            //indexes_g0[i]=-1*indexes_h1[i];
        }
        return g0;
    }
    
    public double[] calculate_g1(double alpha, double [] h0){
        double [] g1;
        g1=new double[h0.length];
        int wym=g1.length-1;
        //alpha*-1,n*h1[-n]
        for(int i=0; i<=wym; i++){
            g1[i]=alpha*Math.pow(-1,indexes_h0[wym-i])*h0[wym-i];
            //System.out.println("Wynik H0, index, G1["+i+"]="+h0[wym-i]+", "+indexes_h0[wym-i]+", "+g1[i]);
            //indexes_g0[i]=-1*indexes_h1[i];
        }
        return g1;
    }
    
    public double calculateAlpha(double []h0, double [] h1){
        double norm1, norm2, norm3, norm4;
        
        
        
        switch(currentFilter){
            case DAUBECHIES_97:
                                indexes_h0=new double[h0.length];
                                indexes_h1=new double[h1.length];
                                for(int j=-4,i=0;j<=4;j++,i++)
                                    indexes_h0[i]=j;
                                for(int j=-4,i=0;j<=2;j++,i++)
                                    indexes_h1[i]=j;
                                break;
                                
            case INTEGER_53:
                                indexes_h0=new double[h0.length];
                                indexes_h1=new double[h1.length];
                                for(int j=-2,i=0;j<=2;j++,i++)
                                    indexes_h0[i]=j;
                                for(int j=-1,i=0;j<=1;j++,i++)
                                    indexes_h1[i]=j;
                                break;                    
            default:
        }
        
        norm1=0;
        norm2=0;
        norm3=0;
        norm4=0;
        
        for(int i=0; i<h0.length; i++){
            norm1+=h0[i];
            norm4+=( Math.pow(-1,indexes_h0[i])*h0[i]);
        }
        for(int i=0; i<h1.length; i++){
            norm3+=h1[i];
            
            norm2+=( Math.pow(-1,indexes_h1[i])*h1[i]);
        }
       
        double norm=((norm1*norm2) +(norm3*norm4));
        if(norm==0){
            norm=2;
            //throw (new ArithmeticException("Division by zero in calculation of Alpha component for "+currentFilter+" wavelet filter "));
        }
        isAlpha=true;    
        return Math.abs(2/norm);
        
    }//end of calculateAlpha
    
    public void resetAlpha(){
        isAlpha=false;
    }//end of resetAlpha()
    
    public double [] sample(double []data, int freq, int start){
        int size=(int)(data.length/freq);
        double [] result = new double[size];
        
        for(int i=0, j=start; i<result.length; i++,j+=freq){
            result[i]=data[j];
        }
        return result;
    }
    
    public double [] zeroFill(double []data, int freq, int start){
        int size=(int)(freq*data.length);
        double [] result = new double[size];
        
        for(int i=0, j=0; i<result.length; i++){
            if(((i+start)%freq)==0)
                result[i]=0;
            else{
                result[i]=data[j];
                j++;
            }
        }
        return result;
    }
    
    
    public static void main(String args[]){
        
        //double data[]={10, 20,30,20,10,20,30,20,10,20,30,20,30,20,10,20,30,20,10,20,30,20,30,20,10,20,30,20,10,20,30,20,30,20,10,20,30,20,10,20,30};
        double data[]={100, 100,100,100,200,200,200,200};
        WaveletFilters wf = new WaveletFilters();
        String h0=Arrays.toString(wf.getH0(5));
        String h1=Arrays.toString(wf.getH1(5));
        String g0=Arrays.toString(wf.getG0(5));
        String g1=Arrays.toString(wf.getG1(5));
        
        Convolution con = new Convolution();
        double res1[], res2[];
        res1=con.convolve1D(data,wf.getH0(5),Convolution.SYMMETRIC, false);
        String d=Arrays.toString(data);
        System.out.println("Oto dane org:"+d+"\n Oto filtr: "+h0+", "+h1);

        res2=con.convolve1D(data,wf.getH1(5),Convolution.SYMMETRIC, false);
         String r1=Arrays.toString(res1);
        String r2=Arrays.toString(res2);
        System.out.println("Oto dane: alpha="+wf.alpha+ "\n"+r1+"\n"+r2);
        
        res1=wf.sample(res1,2,1);
        res2=wf.sample(res2,2,0);
        r1=Arrays.toString(res1);
        r2=Arrays.toString(res2);
        System.out.println("Oto dane: sample="+"\n"+r1+"\n"+r2);
        
        res1=wf.zeroFill(res1,2,0);
        res2=wf.zeroFill(res2,2,1);
        r1=Arrays.toString(res1);
        r2=Arrays.toString(res2);
        System.out.println("Oto dane: zaeroFill="+"\n"+r1+"\n"+r2);
        
        res1=con.convolve1D(res1,wf.getG0(5),Convolution.SYMMETRIC, false);
        res2=con.convolve1D(res2,wf.getG1(5),Convolution.SYMMETRIC,false);
        r1=Arrays.toString(res1);
        r2=Arrays.toString(res2);
       
        System.out.println("Oto dane: alpha="+wf.alpha+ "\n"+r1+"\n"+r2);
         
        System.out.println("Oto dane: alpha="+wf.alpha+ "\n"+h0+"\n"+h1+"\n"+g0+"\n"+g1);
        
        double res[]=new double[res1.length];
        for(int l=0; l<res.length; l++){
            res[l]=res1[l]+res2[l];
        }
        r1=Arrays.toString(res);
        System.out.println("Oto wynik po rekonstrukcji"+"\n"+r1+"\n");
        
    }
    
}//end of class WaveletFilters
