001 package org.biojava3.core.sequence.template;
002
003 import java.util.ArrayList;
004 import java.util.Arrays;
005 import java.util.Collection;
006 import java.util.HashMap;
007 import java.util.List;
008 import java.util.Map;
009
010 import org.biojava3.core.exceptions.TranslationException;
011 import org.biojava3.core.sequence.io.template.SequenceCreatorInterface;
012
013
014 public abstract class AbstractCompoundTranslator<F extends Compound, T extends Compound>
015 implements CompoundTranslator<F, T> {
016
017 private final SequenceCreatorInterface<T> creator;
018 private final Map<F, List<T>> mapper;
019 private final CompoundSet<F> fromCompoundSet;
020 private final CompoundSet<T> toCompoundSet;
021
022 public AbstractCompoundTranslator(SequenceCreatorInterface<T> creator,
023 CompoundSet<F> fromCompoundSet, CompoundSet<T> toCompoundSet) {
024 this.creator = creator;
025 this.mapper = new HashMap<F, List<T>>();
026 this.fromCompoundSet = fromCompoundSet;
027 this.toCompoundSet = toCompoundSet;
028 }
029
030 public SequenceCreatorInterface<T> getCreator() {
031 return creator;
032 }
033
034 public CompoundSet<F> getFromCompoundSet() {
035 return fromCompoundSet;
036 }
037
038 public CompoundSet<T> getToCompoundSet() {
039 return toCompoundSet;
040 }
041
042 @SuppressWarnings("unchecked")
043 protected void addStrings(String source, String... targets) {
044 F f = getFromCompoundSet().getCompoundForString(source);
045 for (String t : targets) {
046 addCompounds(f, getToCompoundSet().getCompoundForString(t));
047 }
048 }
049
050 protected void addCompounds(F source, T... targets) {
051
052 List<T> l = mapper.get(source);
053 if ( l == null) {
054 l = new ArrayList<T>();
055 mapper.put(source, l);
056 }
057 l.addAll(Arrays.asList(targets));
058 }
059
060 @Override
061 public List<T> translateMany(F fromCompound) {
062 return mapper.get(fromCompound);
063 }
064
065 @Override
066 public T translate(F fromCompound) {
067 List<T> compounds = translateMany(fromCompound);
068 if (compounds.isEmpty()) {
069 throw new TranslationException("No compounds found for " + fromCompound);
070 }
071 else if (compounds.size() > 1) {
072 throw new TranslationException("Too many compounds found for "
073 + fromCompound);
074 }
075 else {
076 return compounds.get(0);
077 }
078 }
079
080 @Override
081 public List<Sequence<T>> createSequences(Sequence<F> originalSequence) {
082 List<List<T>> workingList = new ArrayList<List<T>>();
083 for (F source : originalSequence) {
084 List<T> compounds = translateMany(source);
085
086 // Translate source to a list of possible compounds; if we have 1 then
087 // just add onto the list. If we have n then start new paths in all
088 // sequences i.e.
089 //
090 // MTAS (A & S have 2 routes) makes
091 // AUG UGG GAU AGU
092 // AUG UGG GAC AGU
093 // AUG UGG GAU AGC
094 // AUG UGG GAC AGC
095 if (compounds.isEmpty()) {
096 throw new TranslationException("Compound " + source + " resulted in "
097 + "no target compounds");
098 }
099 addCompoundsToList(compounds, workingList);
100 }
101
102 postProcessCompoundLists(workingList);
103
104 return workingListToSequences(workingList);
105 }
106
107 protected abstract void postProcessCompoundLists(List<List<T>> compoundLists);
108
109 protected void addCompoundsToList(List<T> compounds, List<List<T>> workingList) {
110 int size = compounds.size();
111 List<List<T>> currentWorkingList = new ArrayList<List<T>>();
112 for (int i = 0; i < size; i++) {
113 boolean last = (i == (size - 1));
114 // If last run we add the compound to the top set of lists & then
115 // add the remaining ones in
116 if (last) {
117 addCompoundToLists(workingList, compounds.get(i));
118 if (!currentWorkingList.isEmpty()) {
119 workingList.addAll(currentWorkingList);
120 }
121 }
122 // Otherwise duplicate the current sequence set and add this compound
123 else {
124 List<List<T>> duplicate = duplicateList(workingList);
125 addCompoundToLists(duplicate, compounds.get(i));
126 currentWorkingList.addAll(duplicate);
127 }
128 }
129 }
130
131 protected List<Sequence<T>> workingListToSequences(List<List<T>> workingList) {
132 List<Sequence<T>> sequences = new ArrayList<Sequence<T>>();
133 for (List<T> seqList : workingList) {
134 sequences.add(getCreator().getSequence(seqList));
135 }
136 return sequences;
137 }
138
139 private List<List<T>> duplicateList(List<List<T>> incoming) {
140 List<List<T>> outgoing = new ArrayList<List<T>>();
141 for (List<T> current : incoming) {
142 outgoing.add(new ArrayList<T>(current));
143 }
144 return outgoing;
145 }
146
147 protected void addCompoundToLists(List<List<T>> list, T compound) {
148
149 if (list.isEmpty()) {
150 list.add(new ArrayList<T>());
151 }
152
153 for (List<T> current : list) {
154 current.add(compound);
155 }
156 }
157
158 @Override
159 public Sequence<T> createSequence(Sequence<F> originalSequence) {
160 Collection<Sequence<T>> sequences = createSequences(originalSequence);
161 if (sequences.size() > 1) {
162 throw new TranslationException("Too many sequences created; "
163 + "createSequence() assumes only one sequence can be created");
164 }
165 else if (sequences.isEmpty()) {
166 throw new TranslationException("No sequences created");
167 }
168 return sequences.iterator().next();
169 }
170
171 }