001    /*
002     * Copyright (c) 1998-2014 ChemAxon Ltd. All Rights Reserved.
003     *
004     * This software is the confidential and proprietary information of
005     * ChemAxon. You shall not disclose such Confidential Information
006     * and shall use it only in accordance with the terms of the agreements
007     * you entered into with ChemAxon.
008     *
009     */
010    package com.chemaxon.overlap.io;
011    
012    import chemaxon.formats.MolExporter;
013    import chemaxon.formats.MolFormatException;
014    import chemaxon.formats.MolImporter;
015    import chemaxon.struc.Molecule;
016    import com.chemaxon.calculations.common.SubProgressObserver;
017    import com.google.common.base.Optional;
018    import com.google.common.collect.ImmutableList;
019    import java.io.IOException;
020    import java.io.ObjectInputStream;
021    import java.io.ObjectOutputStream;
022    import java.io.Serializable;
023    
024    /**
025     * Master molecule storage is a space efficient storage for Molecules.
026     *
027     * <p>
028     * This class is immutable, thread safe and {@link Serializable}.</p>
029     *
030     * @author Gabor Imre
031     */
032    public final class MasterMoleculeStorage implements MasterStorage<Molecule>, Serializable {
033    
034        /**
035         * Serial version.
036         */
037        private static final long serialVersionUID = 0;
038    
039        /**
040         * Formats to try to represent structure.
041         */
042        static final String[] FORMATS = new String[]{"smiles", "cxsmarts", "mrv"};
043    
044    
045    //    /**
046    //     * Source to store for missing structures.
047    //     *
048    //     * <p>
049    //     * This String literal can not be imported using MolImporter#importMol.</p>
050    //     */
051    //    public static final String MISSING_STRUCTURE = "$";
052    
053        /**
054         * Structure sources which can be imported with MolImporter.
055         *
056         * <p>
057         * Since {@link ImmutableList} does not permit <code>null</code> elements missing structures are represented as a
058         * special {@link String} literal stored in
059         */
060        // private final ImmutableList<String> sources;
061        private final CompactStringStorage sources;
062    
063        /**
064         * Construct over valid sources
065         *
066         * @param sources Sources to construct
067         */
068        //MasterMoleculeStorage(ImmutableList<String> sources) {
069        MasterMoleculeStorage(CompactStringStorage sources) {
070            this.sources = sources;
071        }
072    
073        @Override
074        public int size() {
075            return this.sources.size();
076        }
077    
078    //    /**
079    //     * Calculate total represented character count.
080    //     *
081    //     * <p>
082    //     * This method is intended for diagnostics only!</p>
083    //     *
084    //     * @return Sum of String lengths in the storage
085    //     *
086    //     * TODO: Rename to get allocated size count
087    //     */
088    //    @Beta
089    //    public long getTotalCharCount() {
090    //        long ret = 0;
091    //        for (String s : this.sources) {
092    //            ret += s.length();
093    //        }
094    //        return ret;
095    //    }
096    
097        @Override
098        public int getAbsentCount() {
099            return this.sources.getAbsentCount();
100    //        int ret = 0;
101    //        for (String s : this.sources) {
102    //            if (MISSING_STRUCTURE.equals(s)) {
103    //                ret++;
104    //            }
105    //        }
106    //        return ret;
107        }
108    
109        @Override
110        public Optional<Molecule> get(int index) {
111            final Optional<String> source = this.sources.get(index);
112            if (source.isPresent()) {
113                try {
114                    return Optional.of(MolImporter.importMol(source.get()));
115                } catch (MolFormatException ex) {
116                    throw new IllegalStateException(ex);
117                }
118    
119            } else {
120                // missing
121                return Optional.<Molecule>absent();
122            }
123    //        final String ret = this.sources.get(index);
124    //        if (MISSING_STRUCTURE.equals(ret)) {
125    //            // missing
126    //            return Optional.<Molecule>absent();
127    //        } else {
128    //            try {
129    //                return Optional.of(MolImporter.importMol(ret));
130    //            } catch (MolFormatException ex) {
131    //                throw new IllegalStateException(ex);
132    //            }
133    //        }
134        }
135    
136        /**
137         * Convert Molecule to String multiple formats.
138         *
139         * @param mol Molecule to represent
140         * @return First format structure possible to represent
141         */
142        public static String bestEffortConvert(Molecule mol) {
143            for (int i = 0; i < FORMATS.length; i++) {
144                try {
145                    return MolExporter.exportToFormat(mol, FORMATS[i]);
146                } catch (Exception e) {
147                    // It is ok unless this is the last format
148                    if (i == FORMATS.length - 1) {
149                        throw new IllegalArgumentException(e);
150                    }
151                }
152            }
153            // We should not reach this point
154            throw new IllegalStateException();
155        }
156    
157        @Override
158        public String toString() {
159            return "Master molecule storage, size: " + size() + " absents: " + getAbsentCount();
160        }
161    
162        /**
163         * Write into serialized format.
164         *
165         * @param oos Stream to write to
166         * @param po Progress observer to track progress. Work units reflect non-skipped stored entities. Will be closed
167         * upon completion.
168         *
169         * @throws IOException re-thrown
170         */
171        public void serialize(
172                ObjectOutputStream oos,
173                SubProgressObserver po) throws IOException {
174    
175            this.sources.serialize(oos, po);
176    
177        }
178    
179        /**
180         * Deserialize from an object input stream.
181         *
182         * @param ois Stream to read from
183         * @param po Progress observer to track progress. Work units reflect non-skipped stored entities. Will be closed
184         * upon completion.
185         * @return deserialized instance
186         */
187        public static MasterMoleculeStorage deserialize(ObjectInputStream ois, SubProgressObserver po)
188                throws IOException, ClassNotFoundException {
189    
190            final CompactStringStorage sources = CompactStringStorage.deserialize(ois, po);
191            return new MasterMoleculeStorage(sources);
192    
193        }
194    
195    
196    }