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 */
021
022
023package org.biojava.bio.dist;
024
025import java.util.ArrayList;
026import java.util.List;
027
028import org.biojava.bio.symbol.Alphabet;
029import org.biojava.bio.symbol.AlphabetManager;
030import org.biojava.bio.symbol.IllegalAlphabetException;
031
032/**
033 * Default factory for Order-N distributions.
034 *
035 * @author Thomas Down
036 * @author Mark Schreiber
037 * @since 1.1
038 */
039
040public class OrderNDistributionFactory implements DistributionFactory {
041    /**
042     * Factory which used DistributionFactory.DEFAULT to create conditioned
043     * distributions.
044     */
045
046    public static final DistributionFactory DEFAULT;
047
048    static {
049        DEFAULT = new OrderNDistributionFactory(DistributionFactory.DEFAULT);
050    }
051
052    private final DistributionFactory df;
053
054    /**
055     * Construct a new OrderNDistributionFactory with a specified factory
056     * for conditioned distributions.
057     *
058     * @param df The DistributionFactory used for construction new conditioned
059     *           distributions.
060     */
061
062    public OrderNDistributionFactory(DistributionFactory df) {
063        this.df = df;
064    }
065
066
067    /**
068     * Creates an OrderNDistribution of the appropriate type.
069     *
070     * @param alpha the Alphabet should be in a form that clearly indicates the
071     * conditioning and the conditioned alphabet unless it is very obvious. For
072     * example (DNA x DNA) is obvious, ((DNA x DNA x DNA) x DNA) indicates that
073     * (DNA x DNA x DNA) is the conditioning <code>Alphabet</code> and DNA is the
074     * conditioned <code>Alphabet</code>. (DNA x DNA x DNA x DNA) doesn't but
075     * for compatibility with biojava 1.2 this is allowed in the constructor.
076     * As from biojava 1.2.3 or greater this will be internally converted to
077     * ((DNA x DNA x DNA) x DNA) which was the convention implied by biojava 1.2
078     * Calls to the returned <code>Distribution</code>s <code>getAlphabet()</code>
079     * method will return the converted <code>Alphabet</code>.
080     *
081     * @return An OrderNDistribution
082     * @throws IllegalAlphabetException if a Distribution cannot be made with
083     * that <code>Alphabet</code>.
084     */
085    public Distribution createDistribution(Alphabet alpha)
086        throws IllegalAlphabetException
087    {
088        List aList = alpha.getAlphabets();
089        if (
090          aList.size() == 2 &&
091          aList.get(0) == org.biojava.bio.seq.DNATools.getDNA()
092        ) {
093            return new IndexedNthOrderDistribution(alpha, df);
094        } else {
095            //convert things like (DNA x DNA x DNA) to ((DNA x DNA) x DNA)
096            Alphabet conditioned = (Alphabet)aList.get(aList.size()-1);
097            Alphabet conditioning =
098                AlphabetManager.getCrossProductAlphabet(aList.subList(0,aList.size()-1));
099            List l = new ArrayList();
100            l.add(conditioning);
101            l.add(conditioned);
102            alpha = AlphabetManager.getCrossProductAlphabet(l);
103            //System.out.println(alpha.getName());
104            return new GeneralNthOrderDistribution(alpha, df);
105        }
106    }
107}