package turgen.generator;


public class PulseCreator {
    
    public static final int IDX_BAUDRATE=0;
    public static final int IDX_HEAD=1;
    public static final int IDX_LONG=2;
    public static final int IDX_SHORT=3;
    public static final int IDX_SYNC=4;
    
    public static final int SPECIAL_NONE=0;
    public static final int SPECIAL_SILENCE=1;
    public static final int SPECIAL_LOW=2;
    public static final int SPECIAL_HIGH=3;
    
    
    /**Pilot tone prolongation, number of pulses increases with transfer speed
     * @param newWidth New transfer speed
     * @param origWidth Base transfer speed
     * @param numPulses Number of pilot tone pulses for base transfer speed
     * @return Number of pilot tone pulses after prolongation
     */
    public static int prolongatePilotTone(int numPulses,int origWidth,int newWidth) {
        
        double npl=(double)newWidth;
        double origTime=(double)origWidth*(double)numPulses;
        double newPulses=origTime/npl;
        int np=(int)Math.round(newPulses);
        return np;
    }
    
    /*Vygeneruje obdelnikovy puls o delce, ktera je zadana v 44100 Hz samplech
     *@param length Delka pulzu v samplech
     *@param bits pocet bitu na vzorek, 8 nebo 16
     *@param signed znamenkove/neznamenkove
     *@param special 0 = normalni pulz, 1 = pouze dolni, 2 = pouze horni
     *@param polatity 1 = zacit log. 1 , 0 - zacit log.0
     */
    public static byte[] createPulse(int channels,int volume,int length,int bits,boolean signed,int special,int polarity,boolean rightOnly,boolean sinus) {
        
        if (sinus==true) {
            return createHarmonicPulse(channels,volume,length,bits,signed,polarity,rightOnly);
        }
        
        int lo=0;
        int hi=0;
        int minlo=0;
        int maxhi=0;
        int med=0;
        
        
        int[] pulse = new int[length];
        
        double multip=(double)volume/100.0d;
        
        if (signed==true) {
            if (bits==16) {lo=-32768;hi=32767;med=0;} else {lo=-128;hi=127;med=0;}
        }
        else {
            if (bits==16) {lo=0;hi=65535;med=32768;} else {lo=0;hi=255;med=128;}
        }
        
        byte bMedHi=((byte)(med & 0xFF));
        byte bMedLo=((byte)((med & 0xFF00)>>8));
        
        maxhi=hi;
        minlo=lo;
        
        if (signed==true) {
            hi=(int)(hi*multip);
            lo=(int)(lo*multip);
        }
        else {
            hi=(maxhi/2)+((int)((maxhi/2)*multip));
            lo=maxhi-hi;
        }
        
        /*Ochrana proti nepresnym datovym typum*/
        if (hi>maxhi) hi=maxhi;
        if (lo<minlo) lo=minlo;

        /*Special pulse*/
        switch (special) {
            case SPECIAL_SILENCE: {
                hi=med;lo=med;
                break;
            }
            case SPECIAL_LOW: {
                hi=lo;
                break;
            }
            case SPECIAL_HIGH: {
                lo=hi;
            }
                
        }
        
        
        /*Tvorba zakladnich hodnot s uvazenim polarity*/
        if (polarity==1) {
            for(int i=0;i<length/2;i++) {
                pulse[i]=hi;
            }
            for(int i=length/2;i<length;i++) {
                pulse[i]=lo;
            }
        }
        else {
            for(int i=0;i<length/2;i++) {
                pulse[i]=lo;
            }
            for(int i=length/2;i<length;i++) {
                pulse[i]=hi;
            }
        }
        
        /*Prevedeni na pole bytu*/
        byte[] retVal=null;
        int pos=0;
        
        /*Dvoukanalove pulzy*/
        if (channels == 2) {
            if (bits == 16) {
                retVal = new byte[length * 4];
                for (int i = 0; i < pulse.length; i++) {
                    byte blo = (byte) ((pulse[i] & 0x0000FF00) >> 8);
                    byte bhi = (byte) ((pulse[i] & 0x000000FF));
                    if (rightOnly==false) {
                        retVal[pos + 0] = bhi;
                        retVal[pos + 1] = blo;
                    }
                    else {
                        retVal[pos + 0] =bMedHi;
                        retVal[pos + 1] =bMedLo;
                    }
                    retVal[pos + 2] = bhi;
                    retVal[pos + 3] = blo;
                    pos += 4;
                }
            } else {
                retVal = new byte[pulse.length * 2];
                for (int i = 0; i < pulse.length; i++) {
                    byte bhi = (byte) ((pulse[i] & 0x000000FF));
                    if (rightOnly==false) {
                        retVal[pos] = bhi;
                    }
                    else {
                        retVal[pos] = bMedHi;
                    }
                    
                    retVal[pos + 1] = bhi;
                    pos += 2;
                }
            }
        }
        /*Jednokanalove pulzy*/
        else {
            if (bits == 16) {
                retVal = new byte[length * 2];
                for (int i = 0; i < pulse.length; i++) {
                    byte blo = (byte) ((pulse[i] & 0x0000FF00) >> 8);
                    byte bhi = (byte) ((pulse[i] & 0x000000FF));
                    retVal[pos] = bhi;
                    retVal[pos + 1] = blo;
                    pos += 2;
                }
            } else {
                retVal = new byte[pulse.length];
                for (int i = 0; i < pulse.length; i++) {
                    byte bhi = (byte) ((pulse[i] & 0x000000FF));
                    retVal[pos] = bhi;
                    pos += 1;
                }
            }
        }
        
        
        return retVal;
    }

    private static byte[] createHarmonicPulse(int channels, int volume, int length, int bits, boolean signed, int polarity, boolean rightOnly) {
        Double2SampleFactory factory = new Double2SampleFactory(volume,rightOnly);
        Double2Sample d2s = factory.getDouble2Sample(signed, bits, channels);
        
        double twoPi=Math.PI*2;
        
        double[] doubleSamples = new double[length];
        byte[] byteSamples = new byte[channels*(bits/8)*length];
        
        if (polarity==SignalGenerator.FLAG_POLARITY_10) {
        
            for (int i = 0; i < length; i++) {
                double angle = ((double) i / length) * twoPi;
                doubleSamples[i] = Math.sin(angle);
            }
        }
        else {
            for (int i = 0; i < length; i++) {
                double angle = ((double) i / length) * twoPi;
                doubleSamples[i] = -(Math.sin(angle));
            }
        }
        
        d2s.double2Sample(byteSamples, 0, doubleSamples);
        
        return byteSamples;
        
        
    }
    
    
    
    
    
    
}
