001package org.biopax.paxtools.pattern.constraint;
002
003import org.biopax.paxtools.controller.PathAccessor;
004import org.biopax.paxtools.model.BioPAXElement;
005import org.biopax.paxtools.model.level3.*;
006import org.biopax.paxtools.pattern.Match;
007import org.biopax.paxtools.pattern.util.Blacklist;
008import org.biopax.paxtools.pattern.util.RelType;
009
010import java.util.Collection;
011import java.util.Collections;
012import java.util.HashSet;
013import java.util.Set;
014
015/**
016 * After traversing a PhysicalEntity and the Conversion it participates, this constraint takes us to
017 * the Control. The given relation between PhysicalEntity and Conversion is used to filter out
018 * unrelated controls.
019 *
020 * Var0 - PhysicalEntity (participant)
021 * Var1 - Conversion
022 * Var2 - related Control
023 *
024 * @author Ozgun Babur
025 */
026public class RelatedControl extends ConstraintAdapter
027{
028        /**
029         * Relation type between PhysicalEntity and Conversion.
030         */
031        RelType peType;
032
033        /**
034         * Accessor to controller of Control recursively.
035         */
036        PathAccessor controlledOf = new PathAccessor("Conversion/controlledOf*:Control");
037
038        /**
039         * Constructor with the relation type between PhysicalEntity and Conversion.
040         * @param peType relation type between PhysicalEntity and Conversion
041         */
042        public RelatedControl(RelType peType)
043        {
044                this(peType, null);
045        }
046
047        /**
048         * Constructor with the relation type between PhysicalEntity and Conversion, and the blacklist.
049         * @param peType relation type between PhysicalEntity and Conversion
050         * @param blacklist to detect ubiquitous small molecules
051         */
052        public RelatedControl(RelType peType, Blacklist blacklist)
053        {
054                super(3, blacklist);
055                this.peType = peType;
056        }
057
058        /**
059         * This is a generative constraint.
060         * @return true
061         */
062        @Override
063        public boolean canGenerate()
064        {
065                return true;
066        }
067
068        /**
069         * According to the relation between PhysicalEntity and the Conversion, checks of the Control is
070         * relevant. If relevant it is retrieved.
071         * @param match current pattern match
072         * @param ind mapped indices
073         * @return related controls
074         */
075        @Override
076        public Collection<BioPAXElement> generate(Match match, int... ind)
077        {
078                PhysicalEntity pe = (PhysicalEntity) match.get(ind[0]);
079                Conversion conv = (Conversion) match.get(ind[1]);
080
081                if (!((peType == RelType.INPUT && getConvParticipants(conv, RelType.INPUT).contains(pe)) ||
082                        (peType == RelType.OUTPUT && getConvParticipants(conv, RelType.OUTPUT).contains(pe))))
083                        throw new IllegalArgumentException("peType = " + peType +
084                                ", and related participant set does not contain this PE. Conv dir = " +
085                                getDirection(conv) + " conv.id=" + conv.getRDFId() + " pe.id=" +pe.getRDFId());
086
087                boolean rightContains = conv.getRight().contains(pe);
088                boolean leftContains = conv.getLeft().contains(pe);
089                
090                assert rightContains || leftContains : "PE is not a participant.";
091
092                Set<BioPAXElement> result = new HashSet<BioPAXElement>();
093
094                ConversionDirectionType avoidDir = (leftContains && rightContains) ? null : peType == RelType.OUTPUT ?
095                        (leftContains ? ConversionDirectionType.LEFT_TO_RIGHT : ConversionDirectionType.RIGHT_TO_LEFT) :
096                        (rightContains ? ConversionDirectionType.LEFT_TO_RIGHT : ConversionDirectionType.RIGHT_TO_LEFT);
097
098                for (Object o : controlledOf.getValueFromBean(conv))
099                {
100                        Control ctrl = (Control) o;
101                        ConversionDirectionType dir = getDirection(conv, ctrl);
102
103                        if (avoidDir != null && dir == avoidDir) continue;
104
105                        // don't collect this if the pe is ubique in the context of this control
106                        if (blacklist != null && blacklist.isUbique(pe, conv, dir, peType)) continue;
107
108                        result.add(ctrl);
109                }
110                return result;
111        }
112
113}