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.core;
023
024import java.util.ArrayList;
025import java.util.HashMap;
026import java.util.List;
027import uk.ac.roslin.ensembl.config.EnsemblComparaDivision;
028import uk.ac.roslin.ensembl.config.EnsemblCoreObjectType;
029import uk.ac.roslin.ensembl.config.FeatureType;
030import uk.ac.roslin.ensembl.dao.compara.HomologyDAO;
031import uk.ac.roslin.ensembl.dao.factory.DAOComparaFactory;
032import uk.ac.roslin.ensembl.dao.factory.DAOCoreFactory;
033import uk.ac.roslin.ensembl.dao.factory.DAOFactory;
034import uk.ac.roslin.ensembl.dao.factory.DAOSpeciesFactory;
035import uk.ac.roslin.ensembl.datasourceaware.variation.DAVariation;
036import uk.ac.roslin.ensembl.exception.DAOException;
037import uk.ac.roslin.ensembl.exception.RangeException;
038import uk.ac.roslin.ensembl.model.Coordinate.Strand;
039import uk.ac.roslin.ensembl.model.*;
040import uk.ac.roslin.ensembl.model.core.CollectionSpecies;
041import uk.ac.roslin.ensembl.model.core.CoordinateSystem;
042import uk.ac.roslin.ensembl.model.core.CoreObject;
043import uk.ac.roslin.ensembl.model.core.Species;
044import uk.ac.roslin.ensembl.model.database.CollectionCoreDatabase;
045import uk.ac.roslin.ensembl.model.database.CollectionDatabase;
046import uk.ac.roslin.ensembl.model.database.Registry;
047import uk.ac.roslin.ensembl.model.database.SingleSpeciesCoreDatabase;
048import uk.ac.roslin.ensembl.model.database.SingleSpeciesDatabase;
049
050/**
051 *
052 * @author paterson
053 */
054public class DADNASequence extends org.biojava3.core.sequence.DNASequence implements CoreObject, uk.ac.roslin.ensembl.model.core.DNASequence {
055
056    protected DAOFactory daoFactory = null;
057    protected String schemaVersion = null;
058    protected String dbVersion = null;
059    protected Registry registry = null;
060    protected Integer id = null;
061    protected Integer seqRegionID = null;
062    protected String name = null;
063    protected String dbSpeciesName = null;
064    protected Species species = null;
065    protected Integer DBSeqLength = null;
066    protected CoordinateSystem coordSystem = null;
067    protected MappingSet mappings = new MappingSet();
068    protected HashMap<ObjectType, CoordinateSet> mappedRegions
069            = new HashMap<ObjectType, CoordinateSet>();
070    protected HashMap<ObjectType, MappingSet> objectTypeMappings
071            = new HashMap<ObjectType, MappingSet>();
072    protected HashMap<EnsemblComparaDivision, DAOComparaFactory> comparaFactories
073            = new HashMap<EnsemblComparaDivision, DAOComparaFactory>();
074    
075    protected Integer codonTableID = 1; //default universal code
076    protected boolean lazyLoaded = false;
077    HashMap<String,String> adhocAttributes = new HashMap<String,String>();
078    
079    //to simplify Mybatis fetching
080    protected Integer csID = null;
081
082    public DADNASequence() {
083        super();
084
085    }
086
087    public DADNASequence(DAEnsemblDNASequenceReader proxyLoader) {
088        super(proxyLoader);
089        ((DAEnsemblDNASequenceReader) this.getProxySequenceReader()).setParent(this);
090        this.setId(proxyLoader.getSeqRegionID());
091        this.setDBSeqLength(proxyLoader.getLengthInteger());
092    }
093
094    public DADNASequence(String sequence) {
095        super(new DAEnsemblDNASequenceReader());
096        ((DAEnsemblDNASequenceReader) this.getProxySequenceReader()).setParent(this);
097        ((DAEnsemblDNASequenceReader) this.getProxySequenceReader()).setContents(sequence);
098    }
099
100    public DADNASequence(DAOCoreFactory factory) {
101        this.setDaoFactory(factory);
102    }
103
104    public void setSequenceStorage(DAEnsemblDNASequenceReader proxyLoader) {
105        this.setProxySequenceReader(proxyLoader);
106        ((DAEnsemblDNASequenceReader) this.getProxySequenceReader()).setParent(this);
107    }
108
109    public DAOCoreFactory getDaoFactory() {
110        return (DAOCoreFactory) daoFactory;
111    }
112
113    public void setDaoFactory(DAOFactory daoFactory) {
114        this.daoFactory = daoFactory;
115        if (this.daoFactory!= null) {
116            this.setSchemaVersion(daoFactory.getEnsemblSchemaVersion());
117            this.setDBVersion(daoFactory.getDBVersion());
118            this.setRegistry((Registry) daoFactory.getRegistry());
119        }
120    }
121
122    @Override
123    public String getSchemaVersion() {
124            return schemaVersion;
125    }
126
127    private void setSchemaVersion(String schemaVersion) {
128        this.schemaVersion = schemaVersion;
129    }
130
131    @Override
132    public String getDBVersion() {
133            return dbVersion;
134    }
135
136    private void setDBVersion(String dbversion) {
137        this.dbVersion = dbversion;
138    }
139
140    public Registry getRegistry() {
141            return registry;
142    }
143
144    public void setRegistry(Registry datasource) {
145        this.registry = datasource;
146    }
147
148    @Override
149    public Integer getId() {
150        return id;
151    }
152
153    @Override
154    public void setId(Integer id) {
155        this.id = id;
156    }
157
158    public String getDBName() {
159        return (daoFactory!= null)?daoFactory.getDatabaseName():null;
160    }
161
162    @Override
163    public Species getSpecies() {
164        if (species == null && this.daoFactory != null && this.daoFactory instanceof DAOSpeciesFactory) {
165            species = ((DAOSpeciesFactory) this.daoFactory).getSpecies();
166        }
167        return species;
168    }
169
170    @Override
171    public void setSpecies(Species species) {
172        this.species = species;
173    }
174
175    @Override
176    public ObjectType getType() {
177        //forces a lazy load so make sure we get CS for all retrieved sequenceIDS in the first query!
178        if (this.getCoordSystem() != null) {
179            return this.getCoordSystem().getType();
180        } else {
181            return EnsemblCoreObjectType.DNASequence;
182        }
183    }
184
185    @Override
186    public Integer getDBSeqLength() {
187        if (DBSeqLength == null) {
188            this.lazyLoad();
189        }
190        if (DBSeqLength != null) {
191            return DBSeqLength;
192        } else { return 0;}
193    }
194
195    @Override
196    public void setDBSeqLength(Integer seqLength) {
197        this.DBSeqLength = seqLength;
198        this.setBioEnd(seqLength);
199    }
200
201    @Override
202    public Integer getBioEnd() {
203
204        try {
205            return (super.getBioEnd() != null) ? super.getBioEnd() : this.getDBSeqLength();
206        } catch (NullPointerException e) {
207            return this.getDBSeqLength();
208        }
209    }
210
211    @Override
212    public int getLength() {
213
214        try {
215            return super.getLength();
216        } catch (NullPointerException e) {
217            return this.getDBSeqLength();
218        }
219    }
220
221    @Override
222    public String getName() {
223        if (name == null) {
224            this.lazyLoad();
225        }
226        return name;
227    }
228
229    @Override
230    public void setName(String name) {
231        this.name = name;
232    }
233
234    @Override
235    public CoordinateSystem getCoordSystem() {
236
237        if (coordSystem == null) {
238            this.lazyLoad();
239        }
240
241        return coordSystem;
242    }
243
244    @Override
245    public void setCoordSystem(CoordinateSystem coordSystem) {
246        this.coordSystem = coordSystem;
247    }
248
249    @Override
250    public MappingSet getLoadedMappings() {
251        return this.mappings;
252    }
253
254    //Should Be Private??
255    @Override
256    public MappingSet getLoadedMappings(ObjectType targetType) {
257
258        //need to add lazy load here?
259
260        if (!this.objectTypeMappings.containsKey(targetType)) {
261            return new MappingSet();
262        } else {
263            return this.objectTypeMappings.get(targetType);
264        }
265    }
266
267    @Override
268    public Boolean addMapping(Mapping mapping) {
269
270//        //check we haven't already added a mapping for an object with this id!
271//        if (mapping.getTarget() != null) {
272//
273//            for (Mapping m : this.mappings) {
274//                if (m.getTarget() != null && m.getTarget().getId().equals(mapping.getTarget().getId())) {
275//                    return;
276//                }
277//            }
278//        }
279
280        //if we fail to add the mapping this will be false
281        if (this.mappings.add((Mapping) mapping)) {
282
283            ObjectType t = mapping.getTargetType();
284
285            if (t != null) {
286                if (!this.objectTypeMappings.containsKey(t)) {
287                    this.objectTypeMappings.put(t, new MappingSet());
288                }
289
290                this.objectTypeMappings.get(t).add((Mapping) mapping);
291            }
292            return true;
293        }
294        return false;
295    }
296
297    /**
298     * Returns a List of Genes on the specified Coordinate region. 
299     * @param coord
300     * 
301     * @throws DAOException 
302     */
303    @Override
304    public List<DAGene> getGenesOnRegion(Coordinate coord) throws DAOException {
305
306        List<DAGene> out = new ArrayList<DAGene>();
307
308        List<? extends Mapping> mappings = null;
309
310        //test if we already have got the genes for this coordinate region
311        if (this.mappedRegions.containsKey(FeatureType.gene)
312                && this.mappedRegions.get(FeatureType.gene).containsCoordinateWithoutGaps(coord)) {
313
314            //we need a temporary pointer here so we can match the signatures
315            ArrayList<Mapping> theseMappings = new ArrayList<Mapping>();
316
317            //find and return genes in this region
318            for (Mapping m : this.getLoadedMappings(FeatureType.gene)) {
319                Coordinate c = m.getSourceCoordinates();
320                if (c.overlaps(coord)) {
321                    theseMappings.add(m);
322                }
323            }
324            mappings = theseMappings;
325
326            if (mappings == null || mappings.isEmpty()) {
327                return out;
328            } else {
329                //these mappings are seq -> gene
330
331                if (coord.getStrand() == null) {
332                    for (Mapping m : mappings) {
333                        out.add((DAGene) m.getTarget());
334                        //already done in the DAO
335                        //this.addMapping(m);
336
337                    }
338                } else {
339                    for (Mapping m : mappings) {
340                        if (m.getSourceCoordinates().getStrand().equals(coord.getStrand())) {
341                            out.add((DAGene) m.getTarget());
342                        }
343                        //already done in the DAO
344                        //this.addMapping(m);
345                    }
346                }
347            }
348            return out;
349
350        } else {
351
352            if (this.getDaoFactory() != null && this.getDaoFactory().getGeneDAO() != null) {
353
354                mappings = this.getDaoFactory().getGeneDAO().getGeneMappingsOnRegion(this, coord);
355            }
356
357            if (mappings == null || mappings.isEmpty()) {
358                return out;
359            } else {
360                //these mappings ade gene->seq
361                if (coord.getStrand() == null) {
362                    for (Mapping m : mappings) {
363                        out.add((DAGene) m.getSource());
364                        //already done in the DAO
365                        //this.addMapping(m);
366
367                    }
368                } else {
369                    for (Mapping m : mappings) {
370                        if (m.getTargetCoordinates().getStrand().equals(coord.getStrand())) {
371                            out.add((DAGene) m.getSource());
372                        }
373                        //already done in the DAO
374                        //this.addMapping(m);
375                    }
376                }
377            }
378
379            //put this region in the sore of mapped regions
380            if (!mappedRegions.containsKey(FeatureType.gene)) {
381                mappedRegions.put(FeatureType.gene, new CoordinateSet());
382            }
383            this.mappedRegions.get(FeatureType.gene).add(coord);
384            return out;
385        }
386    }
387
388    /**
389     * Returns a List of Genes on the specified Region. Start/Stop locations must be 
390     * both Non-Null and Non-ZERO or a Runtime IllegalArgumentException will be thrown. 
391     * @param start
392     * @param stop
393     * @param strand
394     * 
395     * @throws DAOException 
396     */
397    @Override
398    public List<DAGene> getGenesOnRegion(Integer start, Integer stop, Strand strand) throws DAOException {
399        Coordinate coord = new Coordinate(start, stop, strand);
400        return this.getGenesOnRegion(coord);
401    }
402
403    /**
404     * Returns a List of Genes on the specified Region. Start/Stop locations must be 
405     * both Non-Null and Non-ZERO or a Runtime IllegalArgumentException will be thrown. 
406     * @param start
407     * @param stop
408     * 
409     * @throws DAOException 
410     */
411    @Override
412    public List<DAGene> getGenesOnRegion(Integer start, Integer stop) throws DAOException {
413
414        return this.getGenesOnRegion(start, stop, null);
415    }
416
417    /**
418     * Private lazyLoad method for validation of essential properties of this object. 
419     * Refetchs the DNASequence by ID, and fills in Name,Length, CoordSystem, Attributes. 
420     */
421    private void lazyLoad() {
422
423        if (!this.lazyLoaded && this.id != null && this.getDaoFactory() != null) {
424            try {
425                DADNASequence fetchedSeq = (DADNASequence) this.getDaoFactory().getSequenceDAO().getSequenceByID(id);
426                this.setName(fetchedSeq.getName());
427                this.setDBSeqLength(fetchedSeq.getDBSeqLength());
428                this.setCoordSystem(fetchedSeq.getCoordSystem());
429                this.setAttributes(fetchedSeq.getAttributes());
430                this.lazyLoaded = true;
431                
432            } catch (Exception ex) {
433            }
434        }
435    }
436    
437    /**
438     * Method to get a string representation of the sequence for the given range. 
439     * Arguments outwith the extent of the sequence (i.e. greater than its length, or less than the start site of +1) 
440     * will throw a RangeException.   
441     * @param begin
442     * @param end
443     * @throws RangeException
444     */
445    @Override
446    public String getSequenceAsString(Integer begin, Integer end) throws RangeException {
447        if (begin==null || begin==0 || end==null || end==0) {
448            throw new IllegalArgumentException("The position 0 is meaningless in the Ensembl DNA world."
449                    +" Use -1 for one base upstream or +1 for the first base.");
450        }        
451        if (this.getLength()==0) {
452            return "";
453        }
454        if (begin>end) {
455            int temp = begin;
456            begin = end;
457            end = temp;
458        }
459        if (begin < this.getBioBegin() || end>this.getLength()) {
460            throw new RangeException("Requested Sequence is outwith the extent of the Sequence (from +1 to 'length')."
461                    +" Try using 'getPaddedSequenceAsString(int, int)' method.");
462        }
463        
464        return super.getSequenceAsString(begin, end, org.biojava3.core.sequence.Strand.POSITIVE);
465    }
466    
467    /**
468     * Method to get a string representation of the sequence for the given range. 
469     * If the requested range is outwith the sequence extent, 
470     * the upstream and or downstream will be padded with N's.
471     * @param begin
472     * @param end
473     */
474    @Override
475    public String getPaddedSequenceAsString(Integer begin, Integer end) {
476        if (begin==null || begin==0 || end==null || end==0) {
477            throw new IllegalArgumentException("The position 0 is meaningless in the Ensembl DNA world."
478                    +" Use -1 for one base upstream or +1 for the first base.");
479        }        
480        if (this.getLength()==0) {
481            return "";
482        }
483        
484        if (begin>end) {
485            int temp = begin;
486            begin = end;
487            end = temp;
488        }
489        
490        int up = 0, down = 0;
491        if (begin < this.getBioBegin()) {
492            if (begin<0) {
493               up = this.getBioBegin()-(begin+1);
494            } else {
495               up = this.getBioBegin()-begin; 
496            }
497            
498            begin = this.getBioBegin();
499        }
500        if (end>this.getLength()) {
501            down = end - this.getLength();
502            end = this.getLength();
503        }
504        
505        return pad(super.getSequenceAsString(begin, end, org.biojava3.core.sequence.Strand.POSITIVE), up, down);
506    }
507
508    /**
509     * Private method to pad a string representation of a sequence with given
510     * numbers of upstream and downstream unknown bases.
511     * @param seq String: the sequence top be padded.
512     * @param upstream int: the number of upstream unknown bases to be prepended.
513     * @param downstream int: the number of downstream unknown bases to be appended.
514     */
515    private String pad(String seq, int upstream, int downstream) {
516       return  GapSequence.getGapString(upstream).concat(seq).concat(GapSequence.getGapString(downstream));
517    }
518
519    /**
520     * Don't use Strands for getting sequence strings - always use getSequenceAsString
521     * or getReverseComplementSequenceAsString to guarantee polarity.
522     */    
523    @Deprecated
524    @Override
525    public String getSequenceAsString(Integer bioStart, Integer bioEnd, org.biojava3.core.sequence.Strand strand) {
526         if (bioStart==null || bioStart==0 || bioEnd==null || bioEnd==0) {
527            throw new IllegalArgumentException("The position 0 is meaningless in the Ensembl DNA world."
528                    +" Use -1 for one base upstream or +1 for the first base.");
529        }
530        
531        try {
532            if (strand != null && strand == org.biojava3.core.sequence.Strand.NEGATIVE) {
533                return getReverseComplementSequenceAsString(bioStart, bioEnd);
534            } else {
535                return getSequenceAsString(bioStart, bioEnd);
536            }
537        } catch (RangeException rangeException) {
538            throw new RuntimeException("Deprecated method caught a RangeException.", rangeException);
539        }
540    }
541    
542    /**
543     * Method to get a string representation of the reverse complement of the
544     * sequence for the given range.
545     * Arguments outwith the extent of the sequence (i.e. greater than its length, or less than the start site of +1) 
546     * will throw a RangeException.      
547     * @param begin
548     * @param end
549     * @return String
550     * @throws RangeException 
551     */
552    @Override
553    public String getReverseComplementSequenceAsString(Integer begin, Integer end) throws RangeException {
554        if (begin==null || begin==0 || end==null || end==0) {
555            throw new IllegalArgumentException("The position 0 is meaningless in the Ensembl DNA world."
556                    +" Use -1 for one base upstream or +1 for the first base.");
557        }
558        if (this.getLength()==0) {
559            return "";
560        }
561        if (begin>end) {
562            int temp = begin;
563            begin = end;
564            end = temp;
565        }
566        if (begin < this.getBioBegin() || end>this.getLength()) {
567            throw new RangeException("Requested Sequence is outwith the extent of the Sequence (from +1 to 'length')"
568                    +" Try using 'getPaddedSequenceAsString(int, int)' method.");
569        }
570        DAEnsemblDNASequenceReader ss = (DAEnsemblDNASequenceReader) getProxySequenceReader();
571        return ss.getReverseComplementSequenceAsString(begin, end);
572    }
573    
574    /**
575     * Method to get a string representation of the reverse complement of the
576     * sequence for the given range. If the requested range is outwith the sequence extent, 
577     * the upstream and or downstream will be padded with N's.
578     * @param begin
579     * @param end
580     */
581    @Override
582    public String getPaddedReverseComplementSequenceAsString(Integer begin, Integer end) {
583        if (begin ==null || begin==0 || end==null|| end ==0 ) {
584            throw new IllegalArgumentException("The position 0 is meaningless in the Ensembl DNA world."
585                    +" Use -1 for one base upstream or +1 for the first base.");
586        }
587        
588        if (this.getLength()==0) {
589            return "";
590        }
591        
592        if (begin>end) {
593            int temp = begin;
594            begin = end;
595            end = temp;
596        }
597        
598        int up = 0, down = 0;
599        
600        if (begin < this.getBioBegin()) {
601            
602            if (begin<0) {
603               up = this.getBioBegin()-(begin+1);
604            } else {
605               up = this.getBioBegin()-begin; 
606            }
607            
608            begin = this.getBioBegin();
609        }
610        if (end>this.getLength()) {
611            down = end - this.getLength();
612            end = this.getLength();
613        }
614        
615        
616        DAEnsemblDNASequenceReader ss = (DAEnsemblDNASequenceReader) getProxySequenceReader();
617        //note we switch the up/down cos on complement
618        return pad(ss.getReverseComplementSequenceAsString(begin, end),down,up);
619    }
620
621    /**
622     * Method to get a string representation of the reverse complement of the
623     * sequence.
624     */
625    @Override
626    public String getReverseComplementSequenceAsString() {
627        if (this.getLength()==0) {
628            return "";
629        }      
630        DAEnsemblDNASequenceReader ss = (DAEnsemblDNASequenceReader) getProxySequenceReader();
631        return ss.getReverseComplementSequenceAsString(this.getBioBegin(), this.getBioEnd());        
632    }
633
634    @Override
635    public HashMap<ObjectType, MappingSet> getObjectTypeMappings() {
636        return objectTypeMappings;
637    }
638
639    @Override
640    public HashMap<ObjectType, CoordinateSet> getMappedRegions() {
641        return mappedRegions;
642    }
643
644    @Override
645    public String getHashID() {
646        return
647                ((this.getDaoFactory()!=null) ? this.getDaoFactory().getDatabaseName() : "NODATABASE")
648
649                +"_"
650
651                +((this.getType()!=null) ? this.getType().toString() : "NOTYPE")
652
653                +"_"
654
655                +((this.getId()!=null) ? this.getId().toString() : "NOID");
656    }
657
658    @Override
659    public String toString() {
660        return ((this.getName()!=null) ? this.getName().toString() : ((this.getId()!=null) ? this.getId().toString() : "NOID"));
661    }
662
663    @Override
664    public void clearAllMappings() {
665            mappings.clear();
666            mappedRegions.clear();
667            objectTypeMappings.clear();
668    }
669
670    /**
671     * Note the special case for Bacteria in collections in DB >16
672     * @return 
673     */
674    public EnsemblComparaDivision getComparaDivision() {
675        
676       if (this.getSpecies() != null && this.getSpecies() instanceof CollectionSpecies
677                && Integer.parseInt(this.getDBVersion())>16) {
678            return EnsemblComparaDivision.PAN_HOMOLOGY;
679       } else if (this.getSpecies() != null) {
680            return this.getSpecies().getComparaDivision();
681       }  
682       return null;
683    }
684
685   public DAOComparaFactory getComparaFactory(EnsemblComparaDivision comparaDivision) {
686
687        if (comparaFactories.containsKey(comparaDivision)) {
688            return comparaFactories.get(comparaDivision);
689        } else if (this.getDaoFactory() != null) {
690            DAOComparaFactory f = this.getDaoFactory().getComparaFactory(comparaDivision);
691            comparaFactories.put(comparaDivision, f);
692            return f;
693        }
694        return null;
695    }
696
697    public DAOComparaFactory getComparaFactory() {
698
699        EnsemblComparaDivision comparaDivision = this.getComparaDivision();
700
701        if (comparaFactories.containsKey(comparaDivision)) {
702            return comparaFactories.get(comparaDivision);
703        } else if (this.getDaoFactory() != null) {
704            DAOComparaFactory f = this.getDaoFactory().getComparaFactory(comparaDivision);
705            comparaFactories.put(comparaDivision, f);
706            return f;
707        }
708        return null;
709    }
710    
711    /**
712     * Specifies method to retrieve all potential regions of conserved synteny 
713     * (i.e. multiple chromosome regions) in the specified target Species 
714     * @param range
715     * @param target
716     * @return a HashMap of each DNASequence discovered against the MappingSet of Homologous genes
717     * @throws DAOException 
718     */    
719    @Override
720    public HashMap<DADNASequence, MappingSet> getRegionsOfConservedSynteny(Coordinate range,
721            Species target) throws DAOException {
722        return this.getRegionsOfConservedSynteny(range, target, null);
723    }
724    
725    /**
726     * Method to retrieve a single potential region of conserved synteny 
727     * for the named chromosome in the specified target Species. In effect a filter 
728     * on the full query, for efficiency where the target chromosome is already known.  
729     * @param range
730     * @param target
731     * @param chrName
732     * @return a HashMap of each DNASequence discovered against the MappingSet of Homologous genes
733     * @throws DAOException 
734     */     
735    @Override
736    public HashMap<DADNASequence, MappingSet> getRegionsOfConservedSynteny(Coordinate range,
737            Species target, String chrName) throws DAOException {
738
739        HashMap<DADNASequence, MappingSet> syntenies = new HashMap<DADNASequence, MappingSet>();
740        
741        if (target == null) {
742            throw new DAOException("No target Species specified for getRegionsOfConservedSynteny");
743        }
744        if (this.getSpecies() == null || this.getComparaDivision() == null) {
745            throw new DAOException("This Sequence does not seem to belong to a species present in comparison databases.");
746        }
747        
748        //for bacterial species from v17 we need to check both of the species are in
749        //pan compara database
750        
751        if (  this.getSpecies() instanceof CollectionSpecies  ) {
752            
753            if (this.getComparaDivision().equals(EnsemblComparaDivision.PAN_HOMOLOGY)
754                    && (!this.getSpecies().isInPanCompara(this.getDBVersion())
755                    || !target.isInPanCompara(this.getDBVersion()))) {
756                return syntenies;
757            }
758
759        }
760        
761
762        try {
763            
764
765            HomologyDAO dao =
766                    this.getComparaFactory().getHomologyDAO();
767
768            syntenies = (HashMap<DADNASequence, MappingSet>) dao.getRegionsOfConservedSynteny(this, range, target, chrName);
769
770            return syntenies;
771        } catch (DAOException dex) {
772            if (dex.getMessage().endsWith("target Species not identified in Compara source")) {
773                return syntenies;
774            }
775            throw new DAOException("Failed to access Compara to get Regions of Conserved Synteny",dex);
776        }
777    }
778
779    @Override
780    public String getAssembly() {
781
782        if (this.getSpecies() == null || this.getDaoFactory() == null
783                || this.getDaoFactory().getDatabase() == null) {
784            return null;
785        }
786
787        try {
788
789            if (this.getSpecies() instanceof CollectionSpecies) {
790                return ((CollectionCoreDatabase) this.getDaoFactory().getDatabase()).getAssemblyName(
791                        (CollectionSpecies) this.getSpecies());
792
793            } else {
794                return ((SingleSpeciesCoreDatabase) this.getDaoFactory().getDatabase()).getAssemblyName();
795
796            }
797        } catch (Exception e) {
798            return null;
799        }
800
801    }
802
803    /**
804     * Returns list of Variations on specified Coordinate Region. Compare to 
805     * {@link getVariationMappingsOnRegion(Coordinate coord)} methods.
806     * @param coord
807     * 
808     * @throws DAOException 
809     */
810    @Override
811    public List<DAVariation> getVariationsOnRegion(Coordinate coord) throws DAOException {
812        
813        //so far i am not adding the variations to the chromosome
814        
815        if (this.getDaoFactory()==null || this.getDaoFactory().getVariationFactory()==null) {
816            return null;
817        }
818        
819        return (List<DAVariation>) this.getDaoFactory().getVariationFactory().getVariationDAO().getVariationsOnRegion(this, coord);
820    }
821
822
823    /**
824     * Returns list of Variations on specified Region.  Compare to 
825     * {@link getVariationMappingsOnRegion(Integer start, Integer stop)} methods. Start/Stop locations must be 
826     * both Non-Null and Non-ZERO or a Runtime IllegalArgumentException will be thrown. 
827     * @param start
828     * @param stop
829     * 
830     * @throws DAOException 
831     */
832     @Override
833    public List<DAVariation> getVariationsOnRegion(Integer start, Integer stop) throws DAOException {
834        return this.getVariationsOnRegion(new Coordinate(start,stop));
835    }
836    
837    
838    /**
839     * Returns List of Mappings of Variations on specified Coordinate Region. Compare to 
840     * {@link getVariationsOnRegion(Coordinate coord)} methods.
841     * @param coord
842     * 
843     * @throws DAOException 
844     */
845     @Override
846    public List<? extends Mapping> getVariationMappingsOnRegion(Coordinate coord) throws DAOException {
847        
848        //so far i am not adding the variations to the chromosome
849        
850        if (this.getDaoFactory()==null || this.getDaoFactory().getVariationFactory()==null) {
851            return null;
852        }
853        
854        return this.getDaoFactory().getVariationFactory().getVariationDAO().getVariationMappingsOnRegion(this, coord);
855    }
856
857    /**
858     * Returns List of Mappings of Variations on specified Coordinate Region. Compare to 
859     * {@link getVariationsOnRegion(Integer start, Integer stop)} methods. Start/Stop locations must be 
860     * both Non-Null and Non-ZERO or a Runtime IllegalArgumentException will be thrown.
861     * @param start
862     * @param stop
863     * 
864     * @throws DAOException 
865     */
866     @Override
867    public List<? extends Mapping> getVariationMappingsOnRegion(Integer start, Integer stop) throws DAOException {
868        return this.getVariationMappingsOnRegion(new Coordinate(start,stop));
869    }
870
871    @Override
872    public Integer getCodonTableID() {
873        this.lazyLoad();
874        return this.codonTableID;
875    }
876    
877    public void setCodonTableID(Integer id) {
878        this.codonTableID=id;
879    }
880
881//    public void fetchAttributes() {
882//        
883//        if (this.lazyLoaded ) {
884//            return;
885//        }
886//        
887//        if(this.getId() != null ) {
888//            try {
889//                this.getDaoFactory().getSequenceDAO().getValidatedSequence(this);
890//            } catch (DAOException ex) {
891//            }
892//        }
893//        
894//        this.lazyLoaded = true;
895//    }
896
897    public void addAttribute(String key, String value) {
898        this.adhocAttributes.put(key, value);
899        updateCodonTableID();
900    }
901    
902    public String getAttribute(String key) {
903        return this.adhocAttributes.get(key);
904    }
905    
906    public void setAttributes(HashMap<String,String> attribs) {
907        this.adhocAttributes = attribs;
908        updateCodonTableID();
909    }
910    
911    public HashMap<String,String>  getAttributes() {
912        return this.adhocAttributes;
913    }
914    
915    private void updateCodonTableID() {
916        if (this.adhocAttributes.containsKey("codon_table")) {
917            this.setCodonTableID(Integer.parseInt(this.adhocAttributes.get("codon_table")));
918        }
919    }
920
921    public void setLazyLoaded(boolean b) {
922        this.lazyLoaded = b;
923    }
924
925    public Integer getCsID() {
926        return csID;
927    }
928
929    public void setCsID(Integer csID) {
930        this.csID = csID;
931    }
932    
933}