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    
011    package com.chemaxon.overlap.unguarded;
012    
013    import com.chemaxon.descriptors.common.Descriptor;
014    import com.chemaxon.descriptors.common.DescriptorComparator;
015    import com.chemaxon.descriptors.common.DescriptorGenerator;
016    import com.google.common.base.Function;
017    import com.google.common.base.Preconditions;
018    import com.google.common.collect.ImmutableList;
019    import java.io.Serializable;
020    import java.util.List;
021    
022    /**
023     * Utility methods related for unguarded descriptors.
024     *
025     *
026     * @author Gabor Imre
027     */
028    public final class Unguardeds {
029    
030        /**
031         * No constructor exposed.
032         */
033        private Unguardeds() {}
034    
035        /**
036         * Wrap a {@link DescriptorGenerator} as an unguarded extractor {@link Function}.
037         *
038         * @param <D> Descriptor type
039         * @param generator Generator to expose
040         * @return Extractor wrapping passed generator
041         */
042        public static <D extends Descriptor> Function<D, byte[]> wrapGenerator(final DescriptorGenerator<D> generator) {
043            return new DescriptorToBytes<D>(generator);
044        }
045    
046        /**
047         * Wrap a {@link DescriptorComparator}.
048         *
049         * <p>The returned {@link UnguardedDissimilarityCalculato} exposes the given comparators
050         * {@link DescriptorComparator#calculateDissimilarity(byte[], byte[]) } method.</p>
051         *
052         * <p>
053         * Note that the function returned by {@link #wrapGenerator(com.chemaxon.descriptors.common.DescriptorGenerator) }
054         * is suitable as the unguarded extractor function.</p>
055         *
056         * @param comparator Comparator to expose
057         * @return Wrapped calculator
058         */
059        public static UnguardedDissimilarityCalculator<byte[]> wrapComparator(final DescriptorComparator<?> comparator) {
060            return new UnguardedWrap(comparator);
061        }
062    
063        /**
064         * Transform a page of descriptors to unguarded form.
065         *
066         * @param <D>           Descriptor type in the original page to be transformed
067         * @param <T>           Unguarded descriptor type
068         * @param extractor     {@link Function} to extract unguarded descriptor content for storage.
069         * @param page          Page to transform
070         * @return              Transformed page
071         */
072        public static <D extends Descriptor, T> ImmutableList<T> transformPage(Function<D, T> extractor, List<D> page) {
073            final ImmutableList.Builder<T> pageBuilder = new ImmutableList.Builder<T>();
074            for (D d: page) {
075                pageBuilder.add(extractor.apply(d));
076            }
077            return pageBuilder.build();
078        }
079    
080        /**
081         * Retrieve byte array representation from a {@link Desscriptor}.
082         *
083         * <p>
084         * Retrieval is done by invoking {@link DescriptorGenerator#toByteArray(com.chemaxon.descriptors.common.Descriptor)}
085         * of the associated {@link DescriptorGenerator}.</p>
086         *
087         * @param <D> Accepted descriptor type
088         */
089        private static class DescriptorToBytes<D extends Descriptor> implements Function<D, byte[]>, Serializable {
090    
091            /**
092             * Serial version.
093             */
094            private static final long serialVersionUID = 0;
095    
096            /**
097             * Underlying generator used for descriptor byte array serialization.
098             */
099            private final DescriptorGenerator<D> generator;
100    
101            /**
102             * Construct.
103             *
104             * @param generator The underlying generator
105             */
106            DescriptorToBytes(DescriptorGenerator<D> generator) {
107                this.generator = generator;
108            }
109    
110            @Override
111            public byte[] apply(D input) {
112                return this.generator.toByteArray(input);
113            }
114    
115            @Override
116            public String toString() {
117                return "Extract bytes representation of " + this.generator.toString();
118            }
119    
120        }
121    
122        /**
123         * Wrap a {@link DescriptorComparator} as an unguarded comparator over the byte array representation.
124         *
125         * <p>
126         * The compared <code>byte []</code> representations of the descriptors are extracted by {@link DescriptorToBytes}
127         * by using {@link DescriptorGenerator#toByteArray(com.chemaxon.descriptors.common.Descriptor)}. The dissimilarity
128         * calculation is done by {@link DescriptorComparator#calculateDissimilarity(byte[], byte[])}.</p>
129         *
130         * @param <D> Type of compared descriptors.
131         */
132        private static class UnguardedWrap implements
133                UnguardedDissimilarityCalculator<byte[]>, Serializable {
134    
135            /**
136             * Serial version.
137             */
138            private static final long serialVersionUID = 0;
139    
140            /**
141             * Underlying comparator.
142             */
143            private final DescriptorComparator<?> comparator;
144    
145            /**
146             * Constructor.
147             *
148             * @param comparator Wrapped comparator, expected to be serializable.
149             */
150            UnguardedWrap(DescriptorComparator<?> comparator) {
151                Preconditions.checkNotNull(comparator);
152                this.comparator = comparator;
153            }
154    
155            @Override
156            public double dissimilarity(byte[] target, byte[] query) {
157                return this.comparator.calculateDissimilarity(target, query);
158            }
159    
160            @Override
161            public String toString() {
162                return "Unguarded dissimiliraty calculator wrapper for " + this.comparator.toString();
163            }
164        }
165    }