001package org.biopax.paxtools.io.sif.level3;
002
003import org.biopax.paxtools.controller.PathAccessor;
004import org.biopax.paxtools.model.BioPAXElement;
005import org.biopax.paxtools.model.level3.*;
006
007import java.util.HashMap;
008import java.util.HashSet;
009import java.util.Map;
010import java.util.Set;
011
012/**
013 * This experimental class is used by Activity Network Analyzer to capture state change events.
014 *
015 * Note: The idea here is similar to converting SBGN-PD to SBGN-ER and this class in the future can be a
016 * basis for that. But currently it makes assumptions about the representation which is compatible with the
017 * existing pathway data sources but might not be compatible with all usages of BioPAX.
018 *
019 * Use with caution.
020 *
021 * @author Emek Demir
022 */
023public class PEStateChange {
024
025        /**
026         * A map of features that are changed and how they changed.
027         */
028        Map<EntityFeature, ChangeType> deltaFeatures;
029
030        /**
031         * A map of changes in the types of controls. For example if as a result of the state change the entity can now
032         * phosphorylate a downstream event, this is registered as a control that is gained.
033         */
034        HashMap<Control, Boolean> deltaControls = new HashMap<Control, Boolean>();
035
036        /**
037         * Left physical entity. Must belong to the same entity reference with right.
038         */
039        SimplePhysicalEntity left;
040
041        /**
042         * Right physical entity, must belong to the same entity reference with left.
043         */
044        SimplePhysicalEntity right;
045
046        /**
047         * Conversion event leading to state change,
048         */
049        Conversion conv;
050
051        /**
052         *
053         */
054        private PhysicalEntity leftRoot;
055    private PhysicalEntity rightRoot;
056    static PathAccessor controllers = new PathAccessor("Conversion/controlledOf/controller");
057
058
059    public PEStateChange(
060            SimplePhysicalEntity left,
061            SimplePhysicalEntity right,
062            PhysicalEntity leftRoot,
063            PhysicalEntity rightRoot,
064            BioPAXElement element,
065            Conversion conv) {
066        this.left = left;
067        this.right = right;
068        this.leftRoot = leftRoot;
069        this.rightRoot = rightRoot;
070        this.conv = conv;
071        this.deltaFeatures = ChangeType.getDeltaFeatures(left, right, leftRoot, rightRoot);
072        calculateDeltaControls();
073    }
074
075
076    @Override
077    public String toString() {
078        return this.left.getStandardName() + "--" + this.right.getDisplayName() + "(" + this.deltaFeatures + ")";
079    }
080
081    @Override
082    public boolean equals(Object o) {
083        if (this == o) return true;
084        if (!(o instanceof PEStateChange)) return false;
085
086        PEStateChange that = (PEStateChange) o;
087
088        if (conv != null ? !conv.equals(that.conv) : that.conv != null) return false;
089        if (deltaFeatures != null ? !deltaFeatures.equals(that.deltaFeatures) : that.deltaFeatures != null)
090            return false;
091        if (left != null ? !left.equals(that.left) : that.left != null) return false;
092        if (right != null ? !right.equals(that.right) : that.right != null) return false;
093
094        return true;
095    }
096
097    public Map<EntityFeature, ChangeType> getDeltaFeatures() {
098        return deltaFeatures;
099    }
100
101    public Conversion getConv() {
102        return conv;
103    }
104
105    public SimplePhysicalEntity getLeft() {
106        return left;
107    }
108
109    public SimplePhysicalEntity getRight() {
110        return right;
111    }
112
113    public SimplePhysicalEntity changedFrom(SimplePhysicalEntity source) {
114        if (this.left == source) return getFlow(true, true);
115        else if (this.right == source) return getFlow(false, false);
116        else return null;
117    }
118
119    public SimplePhysicalEntity changedInto(SimplePhysicalEntity source) {
120        if (this.left == source) return getFlow(true, false);
121        else if (this.right == source) return getFlow(false, true);
122        else return null;
123    }
124
125    private SimplePhysicalEntity getFlow(boolean onLeft, boolean forward) {
126        boolean flow = canFlow(onLeft, forward);
127
128        return flow ? onLeft ? this.right : this.left : null;
129    }
130
131    /**
132     * This method returns true iff conversion can go from/to the side specified by the first parameter in the direction
133     * specified by the second parameter
134     *
135     * @param targetSide true if flow needs to be checked from/to the left side false otherwise
136     * @param forward    true if we are asking if a flow can start from the targetSide, false if we are asking if a flow
137     *                   can go to the targetSide.
138     * @return
139     */
140    private boolean canFlow(boolean targetSide, boolean forward) {
141        boolean flow = true;
142        ConversionDirectionType cd = conv.getConversionDirection();
143        if (cd != null)
144            switch (cd) {
145                case LEFT_TO_RIGHT:
146                    flow = !(targetSide ^ forward);
147                    break;
148                case RIGHT_TO_LEFT:
149                    flow = (targetSide ^ forward);
150                    break;
151                default:
152                    flow = true;
153
154            }
155        return flow;
156    }
157
158    @Override
159    public int hashCode() {
160        int result = deltaFeatures != null ? deltaFeatures.hashCode() : 0;
161        result = 31 * result + (conv != null ? conv.hashCode() : 0);
162        result = 31 * result + (left != null ? left.hashCode() : 0);
163        result = 31 * result + (right != null ? right.hashCode() : 0);
164        return result;
165    }
166
167    public PhysicalEntity getLeftRoot() {
168        return leftRoot;
169    }
170
171    public PhysicalEntity getRightRoot() {
172        return rightRoot;
173    }
174
175    public Map<Control, Boolean> getDeltaControls() {
176        return deltaControls;
177
178    }
179
180    private void calculateDeltaControls() {
181        Set<Control> left = this.leftRoot == null ? null : this.getLeftRoot().getControllerOf();
182        Set<Control> right = this.rightRoot == null ? null : this.getRightRoot().getControllerOf();
183
184        if (left != null)
185            for (Control control : left) {
186                deltaControls.put(control, true);
187            }
188        if (right != null)
189            for (Control control : right) {
190                if (deltaControls.containsKey(control)) {
191                    deltaControls.remove(control);
192                } else
193                    deltaControls.put(control, false);
194
195            }
196
197    }
198
199    public String getControllersAsString() {
200        Set valueFromBean = controllers.getValueFromBean(conv);
201        StringBuilder value = new StringBuilder();
202        for (Object o : valueFromBean) {
203            Controller controller = (Controller) o;
204            value.append(controller.getName()).append( "[");
205                appendXrefs(controller, value);
206                value.append( "] ");
207        }
208        return value.toString();
209    }
210
211        private void appendXrefs(Controller controller, StringBuilder builder)
212        {
213                HashSet<SimplePhysicalEntity> simple = new HashSet<SimplePhysicalEntity>();
214        if(controller instanceof PhysicalEntity) {
215            Simplify.getSimpleMembers((PhysicalEntity) controller, simple);
216            for (SimplePhysicalEntity spe : simple)
217            {
218
219                builder.append("(").append(spe.getEntityReference().getXref()).append(")");
220            }
221        }
222        }
223}