001package org.biopax.paxtools.pattern.constraint;
002
003import org.biopax.paxtools.model.BioPAXElement;
004import org.biopax.paxtools.model.level3.Conversion;
005import org.biopax.paxtools.model.level3.ConversionDirectionType;
006import org.biopax.paxtools.model.level3.PhysicalEntity;
007import org.biopax.paxtools.pattern.Match;
008import org.biopax.paxtools.pattern.util.Blacklist;
009import org.biopax.paxtools.pattern.util.RelType;
010
011import java.util.Collection;
012import java.util.Collections;
013import java.util.HashSet;
014import java.util.Set;
015
016/**
017 * Given Conversion and its one of the participants (at the left or right), traverses to either
018 * the participants at the other side or the same side.
019 *
020 * var0 is a PE (PE1)
021 * var1 is a Conv
022 * var2 is a PE (PE2)
023 *
024 * Prerequisite: PE1 is either at left or right of Conv
025 *
026 * @author Ozgun Babur
027 */
028public class ConversionSide extends ConstraintAdapter
029{
030        /**
031         * Same side or other side;
032         */
033        Type sideType;
034
035        /**
036         * Type of the relation of the participant. It is either input or output.
037         */
038        RelType relType;
039
040        /**
041         * Constructor.
042         *
043         * @param type side type (same side or the other)
044         */
045        public ConversionSide(Type type)
046        {
047                this(type, null, null);
048        }
049
050        /**
051         * Constructor. The relType parameter is using during blacklisting, and only if the blacklist is
052         * not null.
053         *
054         * @param type side type
055         * @param blacklist blacklist of ubiquitous molecules
056         * @param relType relationship type (used together with and during blacklisting)
057         */
058        public ConversionSide(Type type, Blacklist blacklist, RelType relType)
059        {
060                super(3, blacklist);
061
062                if (type == null)
063                {
064                        throw new IllegalArgumentException("The \"type\" parameter cannot be null.");
065                }
066
067                this.sideType = type;
068                this.relType = relType;
069        }
070
071        /**
072         * This is a generative constraint.
073         * @return true
074         */
075        @Override
076        public boolean canGenerate()
077        {
078                return true;
079        }
080
081        /**
082         * Checks which side is the first PhysicalEntity, and gathers participants on either the other
083         * side or the same side.
084         * @param match current pattern match
085         * @param ind mapped indices
086         * @return participants at the desired side
087         */
088        @Override
089        public Collection<BioPAXElement> generate(Match match, int... ind)
090        {
091                assertIndLength(ind);
092
093                PhysicalEntity pe1 = (PhysicalEntity) match.get(ind[0]);
094                Conversion conv = (Conversion) match.get(ind[1]);
095
096                Set<PhysicalEntity> parts;
097
098                if (conv.getLeft().contains(pe1))
099                {
100                        parts = sideType == Type.OTHER_SIDE ? conv.getRight() : conv.getLeft();
101                }
102                else if (conv.getRight().contains(pe1))
103                {
104                        parts = sideType == Type.SAME_SIDE ? conv.getRight() : conv.getLeft();
105                }
106                else throw new IllegalArgumentException(
107                                "The PhysicalEntity has to be a participant of the Conversion.");
108
109                if (blacklist == null) return new HashSet<BioPAXElement>(parts);
110                else
111                {
112                        ConversionDirectionType dir = getDirection(conv);
113
114                        if ((dir == ConversionDirectionType.LEFT_TO_RIGHT && ((relType == RelType.INPUT && parts != conv.getLeft()) || (relType == RelType.OUTPUT && parts != conv.getRight()))) ||
115                                (dir == ConversionDirectionType.RIGHT_TO_LEFT && ((relType == RelType.INPUT && parts != conv.getRight()) || (relType == RelType.OUTPUT && parts != conv.getLeft()))))
116                                return Collections.emptySet();
117
118                        return new HashSet<BioPAXElement>(blacklist.getNonUbiques(parts, relType));
119                }
120        }
121
122        /**
123         * This enum tells if the user want to traverse towards other side of the conversion or stay at
124         * the same side.
125         */
126        public enum Type
127        {
128                OTHER_SIDE,
129                SAME_SIDE
130        }
131}