View Javadoc

1   package uk.ac.ebi.intenz.domain.history;
2   
3   import uk.ac.ebi.intenz.domain.constants.EventConstant;
4   
5   import java.util.*;
6   
7   /**
8    * The directed acyclic history graph stores all events related to an enzyme.
9    * <p/>
10   * The list of all events may include all previous and following events, depending on the state of the regarded enzyme.
11   * This implementation provides standard graph methods such as removing and inserting nodes and events. Each application
12   * of these methods includes a check for cycles.
13   * <p/>
14   * See {@link HistoryEvent} and {@link HistoryNode} for more information about the elements
15   * of the history graph.
16   * <p/>
17   * Instances of this class are immutable.
18   *
19   * @author Michael Darsow
20   * @version $Revision: 1.2 $ $Date: 2008/01/28 12:33:04 $
21   */
22  public class HistoryGraph {
23     /**
24      * The enzyme node for which the history graph is created.
25      */
26     private HistoryNode rootNode;
27  
28     /**
29      * Returns a <code>HistoryGraph</code> instance.
30      *
31      * @param rootNode The root node of the history graph.
32      * @throws NullPointerException if <code>rootNode</code> is empty.
33      */
34     public HistoryGraph (HistoryNode rootNode) {
35        if ( rootNode == null ) throw new NullPointerException("Parameter 'rootNode' must not be null.");
36        this.rootNode = rootNode;
37     }
38  
39     /**
40      * Returns <code>true</code> if this node's event is a <code>DELETION</code> event.
41      * <p/>
42      * This is only the case if the root node is the <code>beforeNode</code> of the event. Otherwise the event is a
43      * <code>CREATION</code> event where the root node represents the <code>afterNode</code>, that is the new entry
44      * an enzyme has been deleted to.
45      *
46      * @return <code>true</code> if the root node's event is of type
47      *         {@link uk.ac.ebi.intenz.domain.constants.EventConstant.DELETION}.
48      */
49     public boolean isDeletedRootNode () {
50        return this.getLatestHistoryEventOfRoot().getEventClass().equals(EventConstant.DELETION)&&
51              this.getLatestHistoryEventOfRoot().getBeforeNode() != null &&
52              this.getLatestHistoryEventOfRoot().getBeforeNode().equals(rootNode);
53     }
54  
55     /**
56      * Returns <code>true</code> if this node's event is a <code>TRANSFER</code> event.
57      * <p/>
58      * This is only the case if the root node is the <code>beforeNode</code> of the event. Otherwise the event is a
59      * <code>CREATION</code> event where the root node represents the <code>afterNode</code>, that is the new entry
60      * an enzyme has been transferred to.
61      *
62      * @return <code>true</code> if the root node's event is of type
63      *         {@link uk.ac.ebi.intenz.domain.constants.EventConstant.TRANSFER}.
64      */
65     public boolean isTransferredRootNode () {
66        return this.getLatestHistoryEventOfRoot().getEventClass().equals(EventConstant.TRANSFER) &&
67              this.getLatestHistoryEventOfRoot().getBeforeNode() != null &&
68              this.getLatestHistoryEventOfRoot().getBeforeNode().equals(rootNode);
69     }
70  
71  
72  
73     // ------------------- GETTER -----------------------------
74  
75     public HistoryNode getRootNode () {
76        return rootNode;
77     }
78  
79     public SortedSet<HistoryEvent> getEdges () {
80        return retrieveEdges(rootNode, new HashSet<HistoryNode>());
81     }
82  
83     /**
84      * Returns the most recent event of the WHOLE graph.
85      *
86      * @return the most recent event.
87      */
88     public HistoryEvent getLatestHistoryEventOfAll () {
89        SortedSet<HistoryEvent> edges = retrieveEdges(rootNode, new HashSet<HistoryNode>());
90        if ( edges.size() == 0 )
91           return new HistoryEvent();
92  	return edges.last();
93     }
94  
95     /**
96      * Returns the most recent event of the root node only.
97      *
98      * @return the most recent event.
99      */
100    public HistoryEvent getLatestHistoryEventOfRoot () {
101       SortedSet<HistoryEvent> edges = new TreeSet<HistoryEvent>(rootNode.getEdges());
102       if ( edges.size() == 0 )
103          return new HistoryEvent();
104 	return edges.last();
105    }
106 
107    /**
108     * Returns the most recent event of the root node only.
109     *
110     * @return the most recent event.
111     */
112    public HistoryEvent getLatestRelevantHistoryEventOfRoot () {
113 	   SortedSet<HistoryEvent> edges = new TreeSet<HistoryEvent>(rootNode.getEdges());
114 	   if ( edges.size() == 0 )
115 		   return new HistoryEvent();
116 	   List<HistoryEvent> list = new ArrayList<HistoryEvent>(edges);
117 	   // count in reverse
118 	   for ( int iii = list.size()-1; iii > -1; iii-- ) {
119 		   HistoryEvent event = list.get(iii);
120 		   // Check if its a transferred node...
121 		   if ( event.getEventClass().equals(EventConstant.TRANSFER) ){
122 			   if ( isTransferredRootNode(event) ) {
123 				   return event;
124 			   }
125 			   continue;
126 		   }
127 
128 		   // Only nodes which have a before_id same as our rootNode are actually modified
129 //		   if( event.getEventClass().equals(EventConstant.MODIFICATION) )
130 //		   if ( isModifiedRootNode(event) )
131 //		   return event;
132 //		   else
133 //		   continue;
134 		   return event;
135 	   }
136 	   return new HistoryEvent();
137    }
138 
139    // ------------------- PRIVATE METHODS --------------------
140 
141    /**
142     * Gets all events this node is part of.
143     *
144     * @param node The node to be looked at.
145     * @return the sorted set of edges (history events).
146     */
147    private SortedSet<HistoryEvent> retrieveEdges (HistoryNode node, Set<HistoryNode> visitedEdges) {
148       assert node != null;
149       visitedEdges.add(node);
150       SortedSet<HistoryEvent> edges = new TreeSet<HistoryEvent>();
151 
152       List<HistoryEvent> currentEdges = node.getEdges();
153       for (Iterator<HistoryEvent> it = currentEdges.iterator(); it.hasNext();) {
154          HistoryEvent event = it.next();
155          HistoryNode relative = event.getRelative(node);
156 
157          if ( relative != null ) {
158             if ( visitedEdges.contains(relative) ) return edges;
159             edges.addAll(retrieveEdges(relative, visitedEdges));
160          }
161 
162          edges.add(event);
163       }
164 
165       return edges;
166    }
167 
168    /**
169     * Returns <code>true</code> if this the event is a <code>TRANSFER</code> event.
170     * <p/>
171     * This is only the case if the root node is the <code>beforeNode</code> of the event. Otherwise the event is a
172     * <code>CREATION</code> event where the root node represents the <code>afterNode</code>, that is the new entry
173     * an enzyme has been transferred to.
174     *
175     * @param event to verify if its a transferred enzyme
176     * @return <code>true</code> if the root node's event is of type
177     *         {@link uk.ac.ebi.intenz.domain.constants.EventConstant#TRANSFER}.
178     */
179    private boolean isTransferredRootNode (HistoryEvent event) {
180       return event.getEventClass().equals(EventConstant.TRANSFER) &&
181             event.getBeforeNode() != null &&
182             event.getBeforeNode().equals(rootNode);
183    }
184 
185    private boolean isModifiedRootNode (HistoryEvent event) {
186       return event.getEventClass().equals(EventConstant.MODIFICATION) &&
187             event.getBeforeNode() != null &&
188             event.getAfterNode().equals(rootNode);
189    }
190 
191    static class HistoryGraphGrid {
192 
193       private TreeMap<List<Integer>, Object> elements;
194       private TreeSet<Integer> xCoordinates;
195       private TreeSet<Integer> yCoordinates;
196 
197       public HistoryGraphGrid () {
198     	  elements = new TreeMap<List<Integer>, Object>(new Comparator<List<Integer>>() {
199     		  public int compare (List<Integer> al1, List<Integer> al2) {
200     			  int x1 = al1.get(0).intValue();
201     			  int y1 = al1.get(1).intValue();
202 
203     			  int x2 = al2.get(0).intValue();
204     			  int y2 = al2.get(1).intValue();
205 
206     			  if ( x1 < x2 ) return -1;
207     			  if ( x1 > x2 ) return 1;
208     			  if ( y1 < y2 ) return -1;
209     			  if ( y1 > y2 ) return 1;
210 
211     			  return 0;
212     		  }
213     	  });
214     	  xCoordinates = new TreeSet<Integer>();
215     	  yCoordinates = new TreeSet<Integer>();
216       }
217 
218       public TreeMap<List<Integer>, Object> getElements () {
219          return elements;
220       }
221 
222       public boolean contains (int x, int y) {
223          List<Integer> coordinates = new ArrayList<Integer>();
224          coordinates.add(new Integer(x));
225          coordinates.add(new Integer(y));
226          return elements.containsKey(coordinates);
227       }
228 
229       public void put (int x, int y, Object value) {
230          List<Integer> coordinates = new ArrayList<Integer>();
231          coordinates.add(new Integer(x));
232          coordinates.add(new Integer(y));
233          elements.put(coordinates, value);
234          xCoordinates.add(new Integer(x));
235          yCoordinates.add(new Integer(y));
236       }
237 
238       public Object getValue (int x, int y) {
239          List<Integer> coordinates = new ArrayList<Integer>();
240          coordinates.add(new Integer(x));
241          coordinates.add(new Integer(y));
242          return elements.get(coordinates);
243       }
244 
245       public void remove (int x, int y) {
246          List<Integer> coordinates = new ArrayList<Integer>();
247          coordinates.add(new Integer(x));
248          coordinates.add(new Integer(y));
249          elements.remove(coordinates);
250          xCoordinates.remove(new Integer(x));
251          yCoordinates.remove(new Integer(y));
252       }
253 
254       public int getMinX () {
255          return xCoordinates.first().intValue();
256       }
257 
258       public int getMaxX () {
259          return xCoordinates.last().intValue();
260       }
261 
262       public int getMinY () {
263          return yCoordinates.first().intValue();
264       }
265 
266       public int getMaxY () {
267          return yCoordinates.last().intValue();
268       }
269 
270    }
271 
272 }