001/**
002 * Copyright (C) 2010-2015 The Roslin Institute <contact andy.law@roslin.ed.ac.uk>
003 *
004 * This file is part of JEnsembl: a Java API to Ensembl data sources developed by the
005 * Bioinformatics Group at The Roslin Institute, The Royal (Dick) School of
006 * Veterinary Studies, University of Edinburgh.
007 *
008 * Project hosted at: http://jensembl.sourceforge.net
009 *
010 * This is free software: you can redistribute it and/or modify
011 * it under the terms of the GNU General Public License (version 3) as published by
012 * the Free Software Foundation.
013 *
014 * This software is distributed in the hope that it will be useful,
015 * but WITHOUT ANY WARRANTY; without even the implied warranty of
016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
017 * GNU General Public License for more details.
018 *
019 * You should have received a copy of the GNU General Public License
020 * in this software distribution. If not, see: http://opensource.org/licenses/gpl-3.0.html
021 */
022package uk.ac.roslin.ensembl.datasourceaware.variation;
023
024import java.util.ArrayList;
025import java.util.HashMap;
026import java.util.HashSet;
027import java.util.List;
028import java.util.Set;
029import org.slf4j.Logger;
030import org.slf4j.LoggerFactory;
031import uk.ac.roslin.ensembl.config.EnsemblCoordSystemType;
032import uk.ac.roslin.ensembl.dao.factory.DAOVariationFactory;
033import uk.ac.roslin.ensembl.datasourceaware.DAObject;
034import uk.ac.roslin.ensembl.exception.NonUniqueException;
035import uk.ac.roslin.ensembl.model.Mapping;
036import uk.ac.roslin.ensembl.model.MappingSet;
037import uk.ac.roslin.ensembl.model.ObjectType;
038import uk.ac.roslin.ensembl.model.core.Chromosome;
039import uk.ac.roslin.ensembl.model.variation.Variation;
040import uk.ac.roslin.ensembl.model.variation.VariationType;
041
042/**
043 *
044 * @author tpaterso
045 */
046public class DAVariation extends DAObject implements Variation {
047
048    final static Logger LOGGER = LoggerFactory.getLogger(DAVariation.class);
049    //use the target comparator for these as will have multiple identical source mappings!
050    protected MappingSet mappings = new MappingSet(Mapping.mappingOnTargetComparator);
051    protected HashMap<ObjectType, MappingSet> objectTypeMappings = new HashMap<ObjectType, MappingSet>();
052    protected Set<ObjectType> mappedObjectTypes = new HashSet<ObjectType>();
053    protected String name;
054    protected String synonym;
055    protected List<String> synonyms = new ArrayList<String>();
056    protected String ancestralAllele;
057    protected DAVariationXRef xref;
058    protected VariationType varType;
059    protected Boolean somatic = false;
060    protected Boolean flipped = false;
061    protected int occurrences;
062    private Boolean initOK = false;
063
064    public DAVariation() {
065        super();
066    }
067
068    public DAVariation(DAOVariationFactory factory) {
069        super(factory);
070    }
071
072    /**
073     * This is a hack to classigy the loaded mapping by type, because MyBatis 
074     * apparently sets 'mappings' by reflection, not
075     * with the setter, so objectTypeMappings is not initialized by the MyBatis call.
076     */
077    public void checkInitialized() {
078        if (!initOK) {
079            for (Mapping mapping : mappings) {
080                ObjectType t = mapping.getTargetType();
081
082                if (t != null) {
083                    if (!this.objectTypeMappings.containsKey(t)) {
084                        this.objectTypeMappings.put(t, new MappingSet());
085                    }
086                    this.objectTypeMappings.get(t).add((Mapping) mapping);
087                }
088            }
089        }
090        initOK = true;
091    }
092
093    @Override
094    public DAOVariationFactory getDaoFactory() {
095        return (DAOVariationFactory) daoFactory;
096    }
097
098    @Override
099    public VariationType getType() {
100        return varType;
101    }
102
103    public void setVarType(VariationType varType) {
104        this.varType = varType;
105    }
106
107    @Override
108    public void addMappedObjectType(ObjectType mappedType) {
109        mappedObjectTypes.add(mappedType);
110    }
111
112    @Override
113    public Boolean isObjectTypeMapped(ObjectType mappedType) {
114        return mappedObjectTypes.contains(mappedType);
115    }
116
117    @Override
118    public Boolean isCurrent() {
119        throw new UnsupportedOperationException("Not supported yet.");
120    }
121
122    /**
123     * Utility method to pull back a single mapping of this Feature on a Given
124     * chromosome. This should be the mapping stored at initialisation. If the
125     * Feature has implemented a reinitialize method this may be called.
126     *
127     * @param chr
128     * @return a single Mapping
129     * @throws NonUniqueException if more than one mapping for the chromosome
130     */
131    @Override
132    public Mapping getChromosomeMapping(Chromosome chr) throws NonUniqueException {
133
134        if (chr == null) {
135            return null;
136        }
137
138        Mapping uniqueMapping = null;
139
140        MappingSet s = this.getLoadedMappings(EnsemblCoordSystemType.chromosome);
141
142        if (s == null || s.isEmpty()) {
143            return null;
144        }
145
146        boolean found = false;
147
148        for (Mapping m : s) {
149            if (m.getTarget() == chr) {
150                if (found) {
151                    throw new NonUniqueException();
152                }
153                uniqueMapping = m;
154                found = true;
155            }
156        }
157        return uniqueMapping;
158    }
159
160    /**
161     * Utility method to pull back a unique chromosomal mapping of this Feature.
162     * This should be the mapping stored at initialisation. If the Feature has
163     * implemented a reinitialize method this may be called.
164     *
165     * @return a single Mapping
166     * @throws NonUniqueException if more than one mapping for the chromosome
167     */
168    @Override
169    public Mapping getChromosomeMapping() throws NonUniqueException {
170
171        Mapping uniqueMapping = null;
172        MappingSet s = this.getLoadedMappings(EnsemblCoordSystemType.chromosome);
173
174        if (s == null || s.isEmpty()) {
175            return null;
176        }
177
178        if (s.size() > 1) {
179            throw new NonUniqueException();
180        }
181
182        return s.first();
183    }
184
185    /**
186     * Method to return all chromosomal mappings for this feature. In most
187     * circumstances there should be only one mapping. If the Feature has
188     * implemented a re-initialize method this may be called.
189     *
190     * @return MappingSet ordered set of chromosomal mappings
191     */
192    @Override
193    public MappingSet getChromosomeMappings() {
194
195        return this.getLoadedMappings(EnsemblCoordSystemType.chromosome);
196    }
197
198    //Should Be Private?? and call by named object type methods ??
199    @Override
200    public MappingSet getLoadedMappings(ObjectType targetType) {
201        this.checkInitialized();
202        if (this.objectTypeMappings.containsKey(targetType)) {
203            return this.objectTypeMappings.get(targetType);
204        } else if (this.isObjectTypeMapped(targetType)) {
205            this.objectTypeMappings.put(targetType, new MappingSet());
206            return this.objectTypeMappings.get(targetType);
207        } else {
208            return new MappingSet();
209        }
210    }
211
212    @Override
213    public MappingSet getLoadedMappings() {
214        //we haven't got the lazy load working here yet
215        return (MappingSet) this.mappings;
216    }
217
218    //added for MyBatis - but it fails to use it - sets by reflection instead
219    public MappingSet getMappings() {
220        //we haven't got the lazy load working here yet
221        return (MappingSet) this.mappings;
222    }
223
224    @Override
225    public Boolean addMapping(Mapping mapping) {
226        //if we fail to add the mapping this will be false
227        if (this.mappings.add((VariationMapping) mapping)) {
228
229            ObjectType t = mapping.getTargetType();
230
231            if (t != null) {
232                if (!this.objectTypeMappings.containsKey(t)) {
233                    this.objectTypeMappings.put(t, new MappingSet());
234                }
235
236                this.objectTypeMappings.get(t).add((Mapping) mapping);
237            }
238            return true;
239        }
240
241        return false;
242    }
243
244    public void setMappings(MappingSet mappings) {
245        for (Mapping m : mappings) {
246            this.addMapping(m);
247        }
248        initOK = true;
249    }
250
251    @Override
252    public void clearAllMappings() {
253        mappings.clear();
254        mappedObjectTypes.clear();
255        objectTypeMappings.clear();
256        initOK = false;
257    }
258
259    @Override
260    public String getName() {
261        return this.name;
262    }
263
264    @Override
265    public void setName(String name) {
266        this.name = name;
267    }
268
269    @Override
270    public DAVariationXRef getXRef() {
271        return xref;
272    }
273
274    public void setXRef(DAVariationXRef xref) {
275        this.xref = xref;
276    }
277
278    @Override
279    public Boolean isSomatic() {
280        return this.somatic;
281    }
282
283    public void setSomatic(Boolean somatic) {
284        this.somatic = somatic;
285    }
286
287    @Override
288    public Boolean isFlipped() {
289        return this.flipped;
290    }
291
292    public void setFlipped(Boolean flipped) {
293        this.flipped = flipped;
294    }
295
296    @Override
297    public String getAncestralAllele() {
298        return this.ancestralAllele;
299    }
300
301    public void setAncestralAllele(String ancestralAllele) {
302        this.ancestralAllele = ancestralAllele;
303    }
304
305    @Override
306    public int getOccurrences() {
307        return this.occurrences;
308    }
309
310    public void setOccurrences(int count) {
311        this.occurrences = count;
312    }
313
314    @Override
315    public String getSynonym() {
316        return this.synonym;
317    }
318
319    @Override
320    public List<String> getAllSynonyms() {
321        return this.synonyms;
322    }
323
324    @Override
325    public void setSynonym(String altname) {
326        this.synonym = altname;
327        this.synonyms.add(altname);
328    }
329}