/* * Copyright 2015 MiLaboratory.com * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.milaboratory.core; import com.milaboratory.core.io.sequence.PairedRead; import com.milaboratory.core.io.sequence.SequenceRead; import com.milaboratory.core.io.sequence.SingleRead; import com.milaboratory.core.sequence.NSequenceWithQuality; public enum PairedEndReadsLayout implements java.io.Serializable { /** * R1 R2 * ---> <--- */ DirectOnly(new PairedTargetProvider( +1, -2), new SingleTargetProvider(false), true), /** * R2 R1 * ---> <--- */ ReverseOnly(new PairedTargetProvider( +2, -1), new SingleTargetProvider(true), true), /** * R1 R2 * ---> <--- * + * R2 R1 * ---> <--- */ Opposite(new PairedTargetProvider( +1, -2, +2, -1), new SingleTargetProvider(false, true), true), /** * R1 R2 * ---> ---> * + * R2 R1 * <--- <--- */ Collinear(new PairedTargetProvider( +1, +2, -2, -1), new SingleTargetProvider(false, true), false), /** * R1 R2 * ---> ---> */ CollinearDirect(new PairedTargetProvider( +1, +2), new SingleTargetProvider(false), false), /** * R1 R2 * ---> <--- * + * R2 R1 * ---> <--- * + * R1 R2 * ---> ---> * + * R2 R1 * <--- <--- */ Unknown(new PairedTargetProvider( +1, -2, +2, -1, +1, +2, -2, -1), new SingleTargetProvider(false, true), false, true); private final PairedTargetProvider pairedProvider; private final SingleTargetProvider singleProvider; /** * Determines possible relative (R1 relative to R2) strands. (true for RC; false for same strand) * * Used only in paired-end reads merger. */ private final boolean[] possibleRelativeStrands; PairedEndReadsLayout(PairedTargetProvider pairedProvider, SingleTargetProvider singleProvider, boolean... possibleRelativeStrands) { this.pairedProvider = pairedProvider; this.singleProvider = singleProvider; this.possibleRelativeStrands = possibleRelativeStrands; } public Target[] createTargets(PairedRead read) { return pairedProvider.createTargets(read); } public Target[] createTargets(SingleRead read) { return singleProvider.createTargets(read); } public Target[] createTargets(SequenceRead read) { if (read instanceof PairedRead) return pairedProvider.createTargets((PairedRead) read); if (read instanceof SingleRead) return singleProvider.createTargets((SingleRead) read); throw new IllegalArgumentException("Unknown read type."); } /** * Determines possible relative (R1 relative to R2) strands. (true for RC; false for same strand) * * Used only in paired-end reads merger. */ public boolean[] getPossibleRelativeStrands() { return possibleRelativeStrands; } private static final class SingleTargetProvider { final boolean[] states; public SingleTargetProvider(boolean... states) { this.states = states; } Target[] createTargets(SingleRead read) { Target[] ts = new Target[states.length]; int i = 0; for (boolean state : states) ts[i++] = new Target(state ? read.getData().getReverseComplement() : read.getData(), state); return ts; } } private static final class PairedTargetProvider { final byte[][] ids; PairedTargetProvider(int... ids) { assert ids.length % 2 == 0; this.ids = new byte[ids.length / 2][]; for (int i = 0; i < ids.length / 2; i++) { this.ids[i] = new byte[]{(byte) ids[i * 2], (byte) ids[i * 2 + 1]}; } } Target[] createTargets(PairedRead read) { final Target[] result = new Target[ids.length]; for (int i = 0; i < ids.length; i++) { byte[] ii = ids[i]; result[i] = new Target(dataFromId(read, ii[0]), dataFromId(read, ii[1]), ii); } return result; } NSequenceWithQuality dataFromId(PairedRead read, byte id) { switch (id) { case +1: return read.getR1().getData(); case +2: return read.getR2().getData(); case -1: return read.getR1().getData().getReverseComplement(); case -2: return read.getR2().getData().getReverseComplement(); } throw new IllegalArgumentException(); } } }