package htsjdk.samtools.util;

import htsjdk.HtsjdkTest;
import java.util.Arrays;
import org.testng.Assert;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

public class SolexaQualityConverterTest extends HtsjdkTest {
    // declared as a staic variable because we reuse it in IlluminaUtilTest
    public static Object[][] SOLEXA_QUALS_TO_PHRED_SCORE = new Object[][] {
        new Object[] {new byte[] {}, new byte[] {}},
        new Object[] {iToB(new int[] {120}), iToB(new int[] {56})},
        new Object[] {iToB(new int[] {64, 65, 120, 121}), iToB(new int[] {3, 4, 56, 57})},
        new Object[] {iToB(new int[] {0, 1, 63}), iToB(new int[] {0, 0, 0})}
    };

    public static Object[][] SOLEXA_QUALS_TO_PHRED_SCORE_1_3 = new Object[][] {
        new Object[] {new byte[] {}, new byte[] {}},
        new Object[] {iToB(new int[] {120}), iToB(new int[] {56})},
        new Object[] {iToB(new int[] {64, 65, 120, 121, 156, 157}), iToB(new int[] {0, 1, 56, 57, 92, 93})},
        new Object[] {iToB(new int[] {0, 1, 63}), iToB(new int[] {-64, -63, -1})}
    };

    public static Object[][] INVALID_SOLEXA_QUALS = new Object[][] {
        new Object[] {iToB(new int[] {-1}), iToB(new int[] {-65})},
        new Object[] {iToB(new int[] {-1, -2}), iToB(new int[] {-65, -66})}
    };

    private static final byte[] iToB(int[] intVals) {
        byte[] byteVals = new byte[intVals.length];
        for (int i = 0; i < byteVals.length; i++) {
            byteVals[i] = (byte) intVals[i];
        }
        return byteVals;
    }

    @DataProvider(name = "solexaQualsToPhredScore")
    public Object[][] solexaQualsToPhredScore() {
        return SOLEXA_QUALS_TO_PHRED_SCORE;
    }

    @DataProvider(name = "solexaQualsToPhredScore_1_3")
    public Object[][] solexaQualsToPhredScore_1_3() {
        return SOLEXA_QUALS_TO_PHRED_SCORE_1_3;
    }

    @DataProvider(name = "invalidSolexaQuals")
    public Object[][] invalidSolexaQuals() {
        return INVALID_SOLEXA_QUALS;
    }

    @Test(dataProvider = "solexaQualsToPhredScore")
    public void solexaQualsToPhredScoreTestArray(byte[] solexaQuals, byte[] phredScores) {
        byte[] qualsToPhred = Arrays.copyOf(solexaQuals, solexaQuals.length);

        SolexaQualityConverter.getSingleton().convertSolexaQualityCharsToPhredBinary(qualsToPhred);
        Assert.assertEquals(phredScores, qualsToPhred);
    }

    @Test(dataProvider = "solexaQualsToPhredScore_1_3")
    public void solexaQualsToPhredScoreTestArray_1_3(byte[] solexaQuals, byte[] phredScores) {
        byte[] qualsToPhred = Arrays.copyOf(solexaQuals, solexaQuals.length);

        SolexaQualityConverter.getSingleton().convertSolexa_1_3_QualityCharsToPhredBinary(qualsToPhred);
        Assert.assertEquals(phredScores, qualsToPhred);
    }

    @Test(dataProvider = "invalidSolexaQuals")
    public void invalidSolexaQualsTestArray(byte[] solexaQuals, byte[] phredScores) {
        byte[] qualsToPhred = Arrays.copyOf(solexaQuals, solexaQuals.length);

        SolexaQualityConverter.getSingleton().convertSolexa_1_3_QualityCharsToPhredBinary(qualsToPhred);
        Assert.assertEquals(phredScores, qualsToPhred);
    }

    @Test(dataProvider = "solexaQualsToPhredScore")
    public void solexaCharToPhredBinaryTest(final byte[] solexaQuals, byte[] phredScores) {
        final SolexaQualityConverter solexaConverter = SolexaQualityConverter.getSingleton();
        for (int i = 0; i < solexaQuals.length; i++) {
            Assert.assertEquals(phredScores[i], solexaConverter.solexaCharToPhredBinary(solexaQuals[i]));
        }
    }

    @Test(dataProvider = "invalidSolexaQuals", expectedExceptions = IndexOutOfBoundsException.class)
    public void invalidSolexaCharToPhredBinaryTest(final byte[] solexaQuals, byte[] phredScores) {
        final SolexaQualityConverter solexaConverter = SolexaQualityConverter.getSingleton();
        for (int i = 0; i < solexaQuals.length; i++) {
            solexaConverter.solexaCharToPhredBinary(solexaQuals[i]);
        }
    }
}
