001 package dk.deepthought.sidious.supportsystem;
002
003 import java.util.ArrayList;
004 import java.util.Collection;
005
006 import org.apache.commons.logging.Log;
007 import org.apache.commons.logging.LogFactory;
008
009 import dk.deepthought.sidious.explanation.Explanation;
010
011 /**
012 * This class represents a list of <code>Adjustable</code> objects and their
013 * setting.
014 *
015 * @author Deepthought
016 *
017 */
018 public class Step {
019
020 /**
021 * The logger for this class.
022 */
023 private static final Log logger = LogFactory.getLog(Step.class);
024
025 /**
026 * The adjustables of this.
027 */
028 private final Collection<Adjustable> adjustables;
029
030 /**
031 * The explanation of this.
032 */
033 private Explanation explanation;
034
035 /**
036 * Constructs a new <code>Step</code> object, specified by the input
037 * <code>adjustables</code>.
038 * <p>
039 * The input adjustables are copied defensively.
040 * <p>
041 * If the input collection is <code>null</code> an empty step is created.
042 * This is to facilitate graphs that do not utilize steps.
043 *
044 * @param adjustables
045 * adjustables associated with this step
046 */
047 public Step(final Collection<Adjustable> adjustables) {
048 if (logger.isDebugEnabled()) {
049 logger.debug("Step(Collection<Adjustable> adjustables="
050 + adjustables + ")");
051 }
052 if (adjustables != null) {
053 this.adjustables = new ArrayList<Adjustable>(adjustables);
054 if (adjustables.isEmpty()) {
055 String fail = "Empty adjustable list not allowed";
056 logger.error(fail);
057 throw new IllegalArgumentException(fail);
058 }
059 } else {
060 this.adjustables = new ArrayList<Adjustable>();
061 }
062 }
063
064 /**
065 * Returns all possible steps emanating from this step.
066 * <p>
067 * The possible steps are calculated by collecting and combining all
068 * possible adjustments of all adjustables of this step.
069 *
070 * @return all possible steps emanating from this step
071 */
072 public Collection<Step> getSteps() {
073 if (logger.isDebugEnabled()) {
074 logger.debug("getSteps() - start");
075 }
076 Collection<Step> steps = new ArrayList<Step>();
077 ArrayList<Adjustable> proxyAdjustables = new ArrayList<Adjustable>(
078 adjustables);
079 for (Adjustable adj : adjustables) {
080 proxyAdjustables.remove(adj);
081 Collection<Adjustable> resultingAdjustables = adj
082 .possibleAdjustments();
083 for (Adjustable newAdj : resultingAdjustables) {
084 proxyAdjustables.add(newAdj);
085 steps.add(new Step(proxyAdjustables));
086 proxyAdjustables.remove(newAdj);
087 }
088 proxyAdjustables.add(adj);
089 }
090 if (logger.isDebugEnabled()) {
091 logger.debug("getSteps() - returned " + steps.size()
092 + " new possible steps");
093 }
094 steps.add(this);// "virgin" step
095 return steps;
096 }
097
098 /**
099 * Calculates the consequence of applying the adjustments of this step to
100 * the input state.
101 *
102 * @param state
103 * the input state
104 * @return the calculated consequence
105 */
106 public State consequence(State state) {
107 if (logger.isDebugEnabled()) {
108 logger.debug("consequence(State state=" + state + ") - start");
109 }
110 if (state == null) {
111 return null;
112 }
113 Collection<State> states = new ArrayList<State>();
114 for (Adjustable adj : adjustables) {
115 states.add(adj.consequence(state));
116 }
117 State returnState = state.impact(states);
118 if (logger.isDebugEnabled()) {
119 logger.debug("consequence(State state=" + state
120 + ") - end - return value=" + returnState);
121 }
122 return returnState;
123 }
124
125 /**
126 * Returns the adjustables of this step.
127 *
128 * @return the adjustables of this step
129 */
130 public Collection<Adjustable> getAdjustables() {
131 return new ArrayList<Adjustable>(adjustables);
132 }
133
134 /**
135 * Sets the explanation of this.
136 *
137 * @param explanation
138 * the explanation
139 */
140 public void setExplanation(Explanation explanation) {
141 this.explanation = explanation;
142 }
143
144 /**
145 * Gets the explanation of this.
146 *
147 * @return the explanation
148 */
149 public Explanation getExplanation() {
150 return explanation;
151 }
152
153 /*
154 * (non-Javadoc)
155 *
156 * @see java.lang.Object#hashCode()
157 */
158 @Override
159 public int hashCode() {
160 final int PRIME = 31;
161 int result = 1;
162 result = PRIME * result
163 + ((adjustables == null) ? 0 : adjustables.hashCode());
164
165 return result;
166 }
167
168 /*
169 * (non-Javadoc)
170 *
171 * @see java.lang.Object#equals(java.lang.Object)
172 */
173 @Override
174 public boolean equals(Object obj) {
175 if (this == obj) {
176 return true;
177 }
178 if (obj == null) {
179 return false;
180 }
181 if (getClass() != obj.getClass()) {
182 return false;
183 }
184 final Step other = (Step) obj;
185 if (adjustables == null) {
186 if (other.adjustables != null) {
187 return false;
188 }
189 } else if (!adjustables.equals(other.adjustables)) {
190 return false;
191 }
192 return true;
193 }
194
195 /*
196 * (non-Javadoc)
197 *
198 * @see java.lang.Object#toString()
199 */
200 @Override
201 public String toString() {
202 return getClass().getSimpleName() + "[adjustables=" + adjustables
203 + ", explanation=" + explanation + "]";
204 }
205
206 }
|