1
2
3
4
5 package com.tomgibara.pronto.state.impl;
6
7 import java.util.ArrayList;
8 import java.util.Collections;
9 import java.util.HashMap;
10 import java.util.HashSet;
11 import java.util.Iterator;
12 import java.util.LinkedList;
13 import java.util.List;
14 import java.util.Set;
15
16 import com.tomgibara.pronto.state.PathType;
17 import com.tomgibara.pronto.state.StateTransition;
18
19 class PathFinder<S, L> {
20
21 private final Set<S> states;
22
23 private final Set<StateTransitionImpl<S, L>> transitions;
24
25 private final HashMap<S, Set<StateTransitionImpl<S, L>>> transitionStates
26 = new HashMap<S, Set<StateTransitionImpl<S, L>>>();
27
28 PathFinder(final Set<S> states, final Set<StateTransitionImpl<S, L>> transitions) {
29 this.states = states;
30 this.transitions = transitions;
31 }
32
33 void addPathsBetween(final S initialState, final Set<S> finalStates,
34 final HashSet<List<StateTransition<S, L>>> paths, final PathType type) {
35
36 S state = initialState;
37
38 final LinkedList<Iterator<StateTransitionImpl<S, L>>> iterators =
39 new LinkedList<Iterator<StateTransitionImpl<S, L>>>();
40
41 final LinkedList<StateTransitionImpl<S, L>> traversed =
42 new LinkedList<StateTransitionImpl<S, L>>();
43
44 final HashSet<StateTransitionImpl<S, L>> uniqueTransitions =
45 type == PathType.uniqueTransitions ? new HashSet<StateTransitionImpl<S, L>>() : null;
46
47 final HashSet<S> uniqueStates =
48 type == PathType.uniqueStates || type == PathType.strictlyUniqueStates ? new HashSet<S>() : null;
49
50
51 if (type == PathType.strictlyUniqueStates) uniqueStates.add(initialState);
52
53 while (true) {
54
55
56 Iterator<StateTransitionImpl<S, L>> i = getTransitionsFromState(state).iterator();
57
58 iterators.add(i);
59
60 if (traversed.size() > 0 && (finalStates == null || finalStates.contains(state))) {
61
62 List<StateTransition<S, L>> path = new ArrayList<StateTransition<S, L>>(traversed);
63
64 paths.add(Collections.unmodifiableList(path));
65 }
66
67
68 StateTransitionImpl<S, L> transition = null;
69
70 outer: while (true) {
71 while (i.hasNext()) {
72 transition = i.next();
73 switch (type) {
74 case uniqueStates:
75 case strictlyUniqueStates:
76 if (!uniqueStates.contains(transition.getTarget())) break outer;
77 break;
78 case uniqueTransitions:
79 if (!uniqueTransitions.contains(transition)) break outer;
80 break;
81 default:
82 throw new IllegalStateException(String
83 .format("Unexpected PathType enumeration value: %s", type));
84 }
85 }
86
87
88
89 iterators.removeLast();
90
91 if (iterators.isEmpty()) {
92
93
94 return;
95 }
96
97
98 i = iterators.getLast();
99
100
101 StateTransitionImpl<S, L> trans = traversed.removeLast();
102
103
104 switch (type) {
105 case uniqueStates:
106 case strictlyUniqueStates:
107 uniqueStates.remove(trans.getTarget());
108 break;
109 case uniqueTransitions:
110 uniqueTransitions.remove(trans);
111 break;
112 default:
113 throw new IllegalStateException(String.format("Unexpected PathType enumeration value: %s", type));
114 }
115 }
116
117
118 traversed.add(transition);
119 state = transition.getTarget();
120
121 switch (type) {
122 case uniqueStates:
123 case strictlyUniqueStates:
124 uniqueStates.add(state);
125 break;
126 case uniqueTransitions:
127 uniqueTransitions.add(transition);
128 break;
129 default:
130 throw new IllegalStateException(String.format("Unexpected PathType enumeration value: %s", type));
131 }
132 }
133 }
134
135 Set<StateTransitionImpl<S, L>> getTransitionsFromState(final S state) {
136 Set<StateTransitionImpl<S, L>> set = transitionStates.get(state);
137 if (set == null) {
138 set = new HashSet<StateTransitionImpl<S, L>>();
139 for (StateTransitionImpl<S, L> transition : transitions) {
140 if (transition.getSource().equals(state)) set.add(transition);
141 }
142 }
143 return set;
144 }
145
146 }