001/**
002 *                  BioJava development code
003 *
004 * This code may be freely distributed and modified under the
005 * terms of the GNU Lesser General Public Licence.  This should
006 * be distributed with the code.  If you do not have a copy,
007 * see:
008 *
009 *      http://www.gnu.org/copyleft/lesser.html
010 *
011 * Copyright for this code is held jointly by the individual
012 * authors.  These should be listed in @author doc comments.
013 *
014 * For more information on the BioJava project and its aims,
015 * or to join the biojava-l mailing list, visit the home page
016 * at:
017 *
018 *      http://www.biojava.org/
019 *
020 * Author: Andreas Prlic
021 *
022 *
023 */
024
025package org.biojava.nbio.structure.scop;
026
027import java.io.BufferedReader;
028import java.io.File;
029import java.io.FileNotFoundException;
030import java.io.IOException;
031import java.io.InputStreamReader;
032import java.net.URL;
033import java.util.ArrayList;
034import java.util.Arrays;
035import java.util.Collections;
036import java.util.HashMap;
037import java.util.List;
038import java.util.Map;
039import java.util.TreeMap;
040import java.util.concurrent.atomic.AtomicBoolean;
041
042import org.biojava.nbio.core.util.FileDownloadUtils;
043import org.biojava.nbio.core.util.InputStreamProvider;
044import org.biojava.nbio.structure.PdbId;
045import org.biojava.nbio.structure.Structure;
046import org.biojava.nbio.structure.StructureTools;
047import org.biojava.nbio.structure.align.util.UserConfiguration;
048import org.slf4j.Logger;
049import org.slf4j.LoggerFactory;
050
051
052/**
053 * This class provides access to the SCOP protein structure classification.
054 *
055 * For more information about SCOP see here:
056 *  <ul>
057 *   <li>SCOP: <a href="http://scop.mrc-lmb.cam.ac.uk/scop/">http://scop.mrc-lmb.cam.ac.uk/scop/</a></li>
058
059 *  <li> Introduction: <a href="http://scop.mrc-lmb.cam.ac.uk/scop/intro.html">http://scop.mrc-lmb.cam.ac.uk/scop/intro.html</a> </li>
060
061 *   <li> SCOP parsable files: <a href="http://scop.mrc-lmb.cam.ac.uk/scop/parse/">http://scop.mrc-lmb.cam.ac.uk/scop/parse/</a> </li>
062 * </ul>
063
064 *
065 * This class can automatically download missing files from the SCOP classification.
066 *
067 * @author Andreas Prlic
068 *
069 */
070public class ScopInstallation implements LocalScopDatabase {
071
072        public static final String DEFAULT_VERSION = ScopFactory.LATEST_VERSION;
073
074        private static final Logger logger = LoggerFactory.getLogger(ScopInstallation.class);
075
076        private String scopVersion;
077
078        // Stores URLs for cla, des, hie, and com files
079        private final List<ScopMirror> mirrors;
080
081        // Cache filenames (with version appended)
082        public static final String claFileName = "dir.cla.scop.txt_";
083        public static final String desFileName = "dir.des.scop.txt_";
084        public static final String hieFileName = "dir.hie.scop.txt_";
085        public static final String comFileName = "dir.com.scop.txt_";
086
087        // Download locations
088        public static final String SCOP_DOWNLOAD = "http://scop.berkeley.edu/downloads/parse/";
089        public static final String SCOP_DOWNLOAD_ALTERNATE = "http://scop.berkeley.edu/downloads/parse/";
090
091        //public static final String NEWLINE = System.getProperty("line.separator");
092        public static final String FILESPLIT = System.getProperty("file.separator");
093
094        private String cacheLocation ;
095
096        private AtomicBoolean installedCla;
097        private AtomicBoolean installedDes;
098        private AtomicBoolean installedHie;
099        private AtomicBoolean installedCom;
100
101        private Map<Integer, List<String>> commentsMap;
102        private Map<String, List<ScopDomain>> domainMap;
103        private Map<Integer, ScopDescription> sunidMap;
104        private Map<Integer, ScopNode> scopTree;
105
106
107        /**
108         * Create a new SCOP installation.
109         *
110         * @param cacheLocation where the SCOP files are stored. If they can't be found at that location they will get automatically downloaded and installed there.
111         */
112        public ScopInstallation(String cacheLocation){
113
114                setCacheLocation(cacheLocation);
115
116                installedCla = new AtomicBoolean();
117                installedCla.set(false);
118                installedDes = new AtomicBoolean();
119                installedDes.set(false);
120                installedHie = new AtomicBoolean();
121                installedHie.set(false);
122                installedCom = new AtomicBoolean();
123                installedCom.set(false);
124
125                scopVersion = DEFAULT_VERSION;
126                mirrors = new ArrayList<ScopMirror>(1);
127
128                domainMap = new HashMap<String, List<ScopDomain>>();
129
130                sunidMap  = new HashMap<Integer, ScopDescription>();
131                scopTree  = new TreeMap<Integer, ScopNode>();
132
133        }
134
135        /**
136         * Removes all of the comments (dir.com file) in order to free memory. The file will need to be reloaded if {@link #getComments(int)} is called subsequently.
137         */
138        public void nullifyComments() {
139                commentsMap = null;
140                installedCom.set(false);
141        }
142
143        /**
144         * Create a new SCOP installation, downloading the file to "the right place".
145         * This will first check for system properties or environmental variables
146         * called {@link UserConfiguration#PDB_CACHE_DIR}, or else will use a temporary directory
147         */
148        public ScopInstallation() {
149                this((new UserConfiguration()).getCacheFilePath());
150        }
151
152        public void ensureClaInstalled() throws IOException {
153                if (installedCla.get()) return;
154                if (!claFileAvailable()) downloadClaFile();
155                parseClassification();
156                installedCla.set(true);
157        }
158
159        public void ensureDesInstalled() throws IOException {
160                if (installedDes.get()) return;
161                if (!desFileAvailable()) downloadDesFile();
162                parseDescriptions();
163                installedDes.set(true);
164        }
165
166        public void ensureComInstalled() throws IOException {
167                if (installedCom.get()) return;
168                if (!comFileAvailable()) downloadComFile();
169                parseComments();
170                installedCom.set(true);
171        }
172
173        public void ensureHieInstalled() throws IOException {
174                if ( installedHie.get()) return;
175                if ( ! hieFileAvailable()) downloadHieFile();
176                parseHierarchy();
177                installedHie.set(true);
178        }
179
180        /* (non-Javadoc)
181         * @see org.biojava.nbio.structure.scop.ScopDatabase#getByCategory(org.biojava.nbio.structure.scop.ScopCategory)
182         */
183        @Override
184        public List<ScopDescription> getByCategory(ScopCategory category){
185
186                try {
187                        ensureDesInstalled();
188                } catch (IOException e) {
189                        throw new ScopIOException(e);
190                }
191
192                List<ScopDescription> matches = new ArrayList<ScopDescription>();
193                for (Integer i : sunidMap.keySet()){
194                        ScopDescription sc = sunidMap.get(i);
195                        if ( sc.getCategory().equals(category))
196
197                                try {
198                                        matches.add((ScopDescription)sc.clone());
199                                } catch (CloneNotSupportedException e) {
200                                        throw new RuntimeException("Could not clone " + ScopDescription.class + " subclass", e);
201                                }
202
203                }
204                return matches;
205        }
206
207        /* (non-Javadoc)
208         * @see org.biojava.nbio.structure.scop.ScopDatabase#filterByClassificationId(java.lang.String)
209         */
210        @Override
211        public List<ScopDescription> filterByClassificationId(String query){
212
213                try {
214                        ensureDesInstalled();
215                } catch (IOException e) {
216                        throw new ScopIOException(e);
217                }
218
219                List<ScopDescription> matches = new ArrayList<ScopDescription>();
220                for (Integer i : sunidMap.keySet()){
221                        ScopDescription sc = sunidMap.get(i);
222
223
224                        if( sc.getClassificationId().startsWith(query)){
225                                matches.add(sc);
226                        }
227                }
228
229                return matches;
230        }
231
232
233        /* (non-Javadoc)
234         * @see org.biojava.nbio.structure.scop.ScopDatabase#getTree(org.biojava.nbio.structure.scop.ScopDomain)
235         */
236        @Override
237        public List<ScopNode> getTree(ScopDomain domain){
238                ScopNode node = getScopNode(domain.getSunid());
239
240
241                List<ScopNode> tree = new ArrayList<ScopNode>();
242                while (node != null){
243
244                        //System.out.println("This node: sunid:" + node.getSunid() );
245                        //System.out.println(getScopDescriptionBySunid(node.getSunid()));
246                        node = getScopNode(node.getParentSunid());
247                        if ( node != null)
248                                tree.add(node);
249                }
250                Collections.reverse(tree);
251                return tree;
252        }
253
254        /* (non-Javadoc)
255         * @see org.biojava.nbio.structure.scop.ScopDatabase#filterByDomainName(java.lang.String)
256         */
257        @Override
258        public List<ScopDomain> filterByDomainName(String query) {
259
260                List<ScopDomain > domains = new ArrayList<ScopDomain>();
261                if (query.length() <5){
262                        return domains;
263                }
264
265                String pdbId = query.substring(1,5);
266
267                List<ScopDomain> doms = getDomainsForPDB(pdbId);
268
269
270                if ( doms == null)
271                        return domains;
272
273                query = query.toLowerCase();
274                for ( ScopDomain d: doms){
275                        if ( d.getScopId().toLowerCase().contains(query)){
276                                domains.add(d);
277                        }
278                }
279
280                return domains;
281        }
282
283        /* (non-Javadoc)
284         * @see org.biojava.nbio.structure.scop.ScopDatabase#filterByDescription(java.lang.String)
285         */
286        @Override
287        public List<ScopDescription> filterByDescription(String query) throws ScopIOException {
288                try {
289                        ensureDesInstalled();
290                } catch (IOException e) {
291                        throw new ScopIOException(e);
292                }
293
294                query = query.toLowerCase();
295                List<ScopDescription> matches = new ArrayList<ScopDescription>();
296                for (Integer i : sunidMap.keySet()){
297                        ScopDescription sc = sunidMap.get(i);
298
299                        if( sc.getDescription().toLowerCase().startsWith(query)){
300                                matches.add(sc);
301                        }
302                }
303
304                return matches;
305        }
306
307
308        /* (non-Javadoc)
309         * @see org.biojava.nbio.structure.scop.ScopDatabase#getScopDescriptionBySunid(int)
310         */
311        @Override
312        public ScopDescription getScopDescriptionBySunid(int sunid) {
313                try {
314                        ensureDesInstalled();
315                } catch (IOException e) {
316                        throw new ScopIOException(e);
317                }
318                return sunidMap.get(sunid);
319        }
320
321        /* (non-Javadoc)
322         * @see org.biojava.nbio.structure.scop.ScopDatabase#getDomainsForPDB(java.lang.String)
323         */
324        @Override
325        public  List<ScopDomain> getDomainsForPDB(String pdbId) {
326
327                try {
328                        ensureClaInstalled();
329                } catch (IOException e) {
330                        throw new ScopIOException(e);
331                }
332
333                List<ScopDomain> doms = domainMap.get(pdbId.toLowerCase());
334
335                List<ScopDomain> retdoms = new ArrayList<ScopDomain>();
336
337                if ( doms == null)
338                        return retdoms;
339
340                for ( ScopDomain d : doms){
341                        try {
342                                ScopDomain n = (ScopDomain) d.clone();
343                                retdoms.add(n);
344                        }  catch (CloneNotSupportedException e){
345                                throw new RuntimeException(ScopDomain.class + " subclass does not support clone()", e);
346                        }
347
348
349                }
350                return retdoms;
351        }
352
353        /* (non-Javadoc)
354         * @see org.biojava.nbio.structure.scop.ScopDatabase#getDomainByScopID(java.lang.String)
355         */
356        @Override
357        public ScopDomain getDomainByScopID(String scopId) {
358
359                try {
360                        ensureClaInstalled();
361                } catch (IOException e) {
362                        throw new ScopIOException(e);
363                }
364
365                if ( scopId.length() < 6) {
366                        throw new ScopIOException("Does not look like a scop ID! " + scopId);
367                }
368                String pdbId = scopId.substring(1,5); //TODO handle this when you handle extended PdbId (PDB ID)
369                List<ScopDomain> doms = getDomainsForPDB(pdbId);
370                if ( doms == null)
371                        return null;
372                for ( ScopDomain d : doms){
373                        if ( d.getScopId().equalsIgnoreCase(scopId))
374                                return d;
375                }
376
377                return null;
378        }
379
380        /* (non-Javadoc)
381         * @see org.biojava.nbio.structure.scop.ScopDatabase#getScopNode(int)
382         */
383        @Override
384        public ScopNode getScopNode(int sunid){
385
386                try {
387                        ensureHieInstalled();
388                } catch (IOException e) {
389                        throw new ScopIOException(e);
390                }
391
392                return scopTree.get(sunid);
393        }
394
395
396        private void parseClassification() throws IOException {
397
398                File file = new File(getClaFilename());
399
400                InputStreamProvider ips = new InputStreamProvider();
401                BufferedReader buffer = new BufferedReader (new InputStreamReader(ips.getInputStream(file)));
402
403                parseClassification(buffer);
404
405        }
406
407        private void parseHierarchy() throws IOException {
408
409                File file = new File(getHieFilename());
410
411
412                InputStreamProvider ips = new InputStreamProvider();
413                BufferedReader buffer = new BufferedReader (new InputStreamReader(ips.getInputStream(file)));
414
415                parseHierarchy(buffer);
416
417        }
418
419        private void parseHierarchy(BufferedReader buffer) throws IOException {
420                String line;
421
422                int counter =0;
423                while ((line = buffer.readLine ()) != null) {
424                        if ( line.startsWith("#"))
425                                continue;
426
427                        String[] spl  = line.split("\t");
428
429                        if ( spl.length != 3 ) {
430                                throw new IOException("parseHierarchy: Can't parse line " + line +" (length: " + spl.length+")");
431                        }
432                        counter++;
433                        int sunid       = Integer.parseInt(spl[0]);
434                        int parentSunid = -1;
435
436                        if ( sunid != 0)
437                                parentSunid = Integer.parseInt(spl[1]);
438
439                        String children = spl[2];
440                        String[] childIds = children.split(",");
441
442                        List<Integer> chis = new ArrayList<Integer>();
443
444                        for ( String id : childIds){
445                                if ( id.equals("-"))
446                                        continue;
447                                chis.add(Integer.parseInt(id));
448                        }
449
450                        ScopNode node = new ScopNode();
451
452                        node.setSunid(sunid);
453                        node.setParentSunid(parentSunid);
454                        node.setChildren(chis);
455
456                        scopTree.put(sunid, node);
457                }
458                logger.info("Parsed {} SCOP sunid nodes.", counter);
459        }
460
461
462        private void parseDescriptions() throws IOException{
463
464                File file = new File(getDesFilename());
465
466                InputStreamProvider ips = new InputStreamProvider();
467                BufferedReader buffer = new BufferedReader (new InputStreamReader(ips.getInputStream(file)));
468
469                parseDescriptions(buffer);
470
471        }
472
473        private void parseComments() throws IOException{
474
475                File file = new File(getComFilename());
476
477                InputStreamProvider ips = new InputStreamProvider();
478                BufferedReader buffer = new BufferedReader (new InputStreamReader(ips.getInputStream(file)));
479
480                parseComments(buffer);
481
482        }
483
484        private void parseComments(BufferedReader buffer) throws IOException {
485
486                commentsMap = new HashMap<Integer,List<String>>();
487
488                int counter = 0;
489                String line;
490                while ((line = buffer.readLine ()) != null) {
491                        if (line.startsWith("#")) continue;
492                        String[] parts = line.split("!");
493                        int sunId = Integer.parseInt(parts[0].trim());
494                        if (parts.length == 1) {
495                                commentsMap.put(sunId, new ArrayList<String>(1));
496                                continue;
497                        }
498                        List<String> comments = new ArrayList<String>(parts.length - 1);
499                        for (int i = 1; i < parts.length; i++) {
500                                String trimmed = parts[i].trim();
501                                if( !trimmed.isEmpty() ) {
502                                        comments.add(trimmed);
503                                }
504                        }
505                        commentsMap.put(sunId, comments);
506                        counter++;
507                }
508                logger.info("Parsed {} SCOP comments.", counter);
509
510        }
511
512        private void parseDescriptions(BufferedReader buffer) throws IOException {
513                String line = null;
514
515                int counter = 0;
516                while ((line = buffer.readLine ()) != null) {
517                        if ( line.startsWith("#"))
518                                continue;
519
520                        String[] spl  = line.split("\t");
521
522                        if ( spl.length != 5 ) {
523                                throw new IOException("parseDescriptions: Can't parse line " + line +" (length: " + spl.length+")");
524                        }
525                        counter++;
526
527                        //46464  dm  a.1.1.2 -   Hemoglobin I
528                        int sunID = Integer.parseInt(spl[0]);
529                        ScopCategory category =  ScopCategory.fromString(spl[1]);
530                        String classificationId = spl[2];
531                        String name = spl[3];
532                        String desc = spl[4];
533
534                        ScopDescription c = new ScopDescription();
535                        c.setSunID(sunID);
536                        c.setCategory(category);
537                        c.setClassificationId(classificationId);
538                        c.setName(name);
539                        c.setDescription(desc);
540
541                        sunidMap.put(sunID, c);
542
543                }
544                logger.info("Parsed {} SCOP sunid descriptions.", counter);
545        }
546
547
548
549        private void parseClassification(BufferedReader buffer) throws IOException {
550                String line = null;
551
552                int counter = 0;
553                while ((line = buffer.readLine ()) != null) {
554                        if ( line.startsWith("#"))
555                                continue;
556
557                        String[] spl  = line.split("\t");
558
559                        if ( spl.length != 6){
560                                throw new IOException("Can't parse line " + line);
561                        }
562                        counter++;
563
564                        String scopId = spl[0];
565                        String pdbId = spl[1];
566                        String range = spl[2];
567                        String classificationId = spl[3];
568                        Integer sunid = Integer.parseInt(spl[4]);
569                        String tree = spl[5];
570
571
572
573                        ScopDomain d = new ScopDomain();
574                        d.setScopId(scopId);
575                        PdbId tempPdbId = null;
576                        try {
577                                tempPdbId = new PdbId(pdbId);
578                        } catch (NullPointerException | IllegalArgumentException e) {
579                                logger.warn("could not parse line >>{}<<. Error Message: {}", line, e.getMessage());
580                        }
581                        d.setPdbId(tempPdbId);
582
583                        d.setRanges(extractRanges(range));
584
585                        d.setClassificationId(classificationId);
586                        d.setSunid(sunid);
587
588                        String[] treeSplit = tree.split(",");
589
590                        if (  treeSplit.length != 7 ) {
591                                throw new IOException("Can't process: " + line );
592                        }
593
594                        int classId =Integer.parseInt(treeSplit[0].substring(3));
595                        int foldId = Integer.parseInt(treeSplit[1].substring(3));
596                        int superfamilyId = Integer.parseInt(treeSplit[2].substring(3));
597                        int familyId = Integer.parseInt(treeSplit[3].substring(3));
598                        int domainId = Integer.parseInt(treeSplit[4].substring(3));
599                        int speciesId = Integer.parseInt(treeSplit[5].substring(3));
600                        int px = Integer.parseInt(treeSplit[6].substring(3));
601
602                        d.setClassId(classId);
603                        d.setFoldId(foldId);
604                        d.setSuperfamilyId(superfamilyId);
605                        d.setFamilyId(familyId);
606                        d.setDomainId(domainId);
607                        d.setSpeciesId(speciesId);
608                        d.setPx(px);
609
610                        List<ScopDomain> domainList;
611                        if ( domainMap.containsKey(pdbId)){
612                                domainList = domainMap.get(pdbId);
613                        } else {
614                                domainList = new ArrayList<ScopDomain>();
615                                domainMap.put(pdbId,domainList);
616                        }
617
618                        domainList.add(d);
619                }
620                logger.info("Parsed {} SCOP sunid domains.", counter);
621
622        }
623
624        /**
625         * Converts the SCOP range field into a list of subranges suitable for
626         * storage in a ScopDomain object. Each range should be of a format
627         * compatible with {@link StructureTools#getSubRanges(Structure,String)}.
628         * @param range
629         * @return
630         */
631        private List<String> extractRanges(String range) {
632                List<String> ranges;
633                String[] rangeSpl = range.split(",");
634
635                // Recent versions of scop always specify a chain, so no processing is needed
636                if(scopVersion.compareTo("1.73") < 0 ) {
637                        for(int i=0; i<rangeSpl.length;i++) {
638                                String subRange = rangeSpl[i];
639
640                                // Allow single-chains, as well as the '-' special case
641                                if(subRange.length()<2) {
642                                        continue;
643                                }
644
645                                // Allow explicit chain syntax
646                                if(subRange.charAt(1) != ':') {
647                                        // Early versions sometimes skip the chain identifier for single-chain domains
648                                        // Indicate this with a chain "_"
649                                        rangeSpl[i] = "_:"+subRange;
650                                }
651                        }
652                }
653                ranges = Arrays.asList(rangeSpl);
654                return ranges;
655        }
656
657        protected void downloadClaFile() throws FileNotFoundException, IOException{
658                if(mirrors.size()<1) {
659                        initScopURLs();
660                }
661                IOException exception = null;
662                for(ScopMirror mirror:mirrors) {
663                        try {
664                                URL url = new URL(mirror.getClaURL(scopVersion));
665
666                                String localFileName = getClaFilename();
667                                File localFile = new File(localFileName);
668
669                                downloadFileFromRemote(url, localFile);
670                                return;
671                        } catch(IOException e ) {
672                                exception = e;
673                        }
674                }
675                throw new IOException("Unable to download SCOP .cla file",exception);
676        }
677
678        protected void downloadDesFile() throws FileNotFoundException, IOException{
679                if(mirrors.size()<1) {
680                        initScopURLs();
681                }
682                IOException exception = null;
683                for(ScopMirror mirror:mirrors) {
684                        try {
685                                URL url = new URL(mirror.getDesURL( scopVersion));
686
687                                String localFileName = getDesFilename();
688                                File localFile = new File(localFileName);
689
690                                downloadFileFromRemote(url, localFile);
691                                return;
692                        } catch(IOException e ) {
693                                exception = e;
694                        }
695                }
696                throw new IOException("Unable to download SCOP .des file",exception);
697        }
698
699        protected void downloadHieFile() throws IOException{
700                if(mirrors.size()<1) {
701                        initScopURLs();
702                }
703                IOException exception = null;
704                for(ScopMirror mirror:mirrors) {
705                        try {
706                                URL url = new URL(mirror.getHieURL( scopVersion));
707
708                                String localFileName = getHieFilename();
709                                File localFile = new File(localFileName);
710
711                                downloadFileFromRemote(url, localFile);
712                                return;
713                        } catch(IOException e ) {
714                                exception = e;
715                        }
716                }
717                throw new IOException("Unable to download SCOP .hie file",exception);
718
719        }
720
721        protected void downloadComFile() throws FileNotFoundException, IOException{
722                if(mirrors.size()<1) {
723                        initScopURLs();
724                }
725                IOException exception = null;
726                for(ScopMirror mirror:mirrors) {
727                        try {
728                                URL url = new URL(mirror.getComURL(scopVersion));
729
730                                String localFileName = getComFilename();
731                                File localFile = new File(localFileName);
732
733                                downloadFileFromRemote(url, localFile);
734                                return;
735                        } catch (IOException e ) {
736                                exception = e;
737                        }
738                }
739                throw new IOException("Unable to download SCOP .com file",exception);
740        }
741
742        protected void downloadFileFromRemote(URL remoteURL, File localFile) throws IOException{
743                logger.info("Downloading " + remoteURL + " to: " + localFile);
744                FileDownloadUtils.downloadFile(remoteURL, localFile);
745        }
746
747        private boolean claFileAvailable(){
748                String fileName = getClaFilename();
749
750                File f = new File(fileName);
751
752                return f.exists() && f.length()>0;
753        }
754
755        private boolean desFileAvailable(){
756                String fileName = getDesFilename();
757
758                File f = new File(fileName);
759                return f.exists() && f.length()>0;
760        }
761
762        private boolean hieFileAvailable(){
763                String fileName = getHieFilename();
764
765                File f = new File(fileName);
766
767                return f.exists() && f.length()>0;
768        }
769
770        private boolean comFileAvailable(){
771                String fileName = getComFilename();
772
773                File f = new File(fileName);
774
775                return f.exists() && f.length()>0;
776        }
777
778        protected String getClaFilename(){
779                return cacheLocation + claFileName + scopVersion;
780        }
781
782        protected String getDesFilename(){
783                return cacheLocation + desFileName + scopVersion;
784
785        }
786
787        protected String getHieFilename(){
788                return cacheLocation + hieFileName + scopVersion;
789
790        }
791
792        protected String getComFilename(){
793                return cacheLocation + comFileName + scopVersion;
794        }
795
796        public String getCacheLocation() {
797                return cacheLocation;
798        }
799
800        public void setCacheLocation(String cacheLocation) {
801
802                if (! cacheLocation.endsWith(FILESPLIT))
803                        cacheLocation += FILESPLIT;
804                this.cacheLocation = cacheLocation;
805
806
807        }
808        /* (non-Javadoc)
809         * @see org.biojava.nbio.structure.scop.ScopDatabase#getScopVersion()
810         */
811        @Override
812        public String getScopVersion() {
813                return scopVersion;
814        }
815        @Override
816        public void setScopVersion(String scopVersion) {
817                if(scopVersion == null)
818                        throw new NullPointerException("Null scop version");
819                if(this.scopVersion.equals(scopVersion))
820                        return;
821                this.scopVersion = scopVersion;
822                // reset installation flags
823                installedCla.set(false);
824                installedDes.set(false);
825                installedHie.set(false);
826                installedCom.set(false);
827
828        }
829
830        public void addMirror(String scopDownloadURL) {
831                mirrors.add(new ScopMirror(scopDownloadURL));
832        }
833        void addMirror(ScopMirror scopURLs) {
834                mirrors.add(scopURLs);
835        }
836        public List<ScopMirror> getMirrors() {
837                if(mirrors.isEmpty()) {
838                        this.initScopURLs();
839                }
840                return mirrors;
841        }
842
843        /* (non-Javadoc)
844         * @see org.biojava.nbio.structure.scop.ScopDatabase#getScopDomainsBySunid(java.lang.Integer)
845         */
846        @Override
847        public List<ScopDomain> getScopDomainsBySunid(Integer sunid)
848        {
849
850                try {
851                        ensureClaInstalled();
852                } catch (IOException e) {
853                        throw new ScopIOException(e);
854                }
855
856                List<ScopDomain> domains = new ArrayList<ScopDomain>();
857
858                for (String pdbId: domainMap.keySet()){
859                        for (ScopDomain d : domainMap.get(pdbId)){
860                                try {
861                                        if ( d.getPx() == sunid) {
862                                                domains.add((ScopDomain)d.clone());
863                                        } else if ( d.getSpeciesId() == sunid ){
864                                                domains.add((ScopDomain)d.clone());
865                                        }else if ( d.getDomainId() == sunid ){
866                                                domains.add((ScopDomain)d.clone());
867                                        }else if ( d.getFamilyId() == sunid ){
868                                                domains.add((ScopDomain)d.clone());
869                                        }else if ( d.getSuperfamilyId() == sunid ){
870                                                domains.add((ScopDomain)d.clone());
871                                        }else if ( d.getFoldId() == sunid ){
872                                                domains.add((ScopDomain)d.clone());
873                                        }else if ( d.getClassId() == sunid ){
874                                                domains.add((ScopDomain)d.clone());
875                                        } else {
876                                                throw new RuntimeException("Type " + d + " not recognized"); // only possible if SCOP changes
877                                        }
878                                } catch (CloneNotSupportedException e){
879                                        throw new RuntimeException(ScopDomain.class + " subclass does not support clone()", e);
880                                }
881                        }
882                }
883                return domains;
884
885        }
886
887        @Override
888        public List<String> getComments(int sunid) {
889                try {
890                        ensureComInstalled();
891                } catch (IOException e) {
892                        throw new ScopIOException(e);
893                }
894                if (!commentsMap.containsKey(sunid)) return new ArrayList<String>(1);
895                return commentsMap.get(sunid);
896        }
897
898
899        private void initScopURLs() {
900                if(!this.mirrors.isEmpty()) {
901                        return;
902                }
903
904                // first, try default scop
905                ScopMirror primary = new ScopMirror();
906                // If unreachable, try alternate Berkeley location
907                ScopMirror alt = new ScopMirror(
908                                SCOP_DOWNLOAD_ALTERNATE,
909                                "dir.cla.scop.%s.txt","dir.des.scop.%s.txt",
910                                "dir.hie.scop.%s.txt","dir.com.scop.%s.txt");
911                mirrors.add(primary);
912                mirrors.add(alt);
913        }
914}