001 package dk.deepthought.sidious.rules;
002 
003 import java.util.Collection;
004 
005 import dk.deepthought.sidious.goalhandler.Goal;
006 import dk.deepthought.sidious.greenhouse.ClimaticState;
007 import dk.deepthought.sidious.greenhouse.SensorInput;
008 import dk.deepthought.sidious.supportsystem.Adjustable;
009 import dk.deepthought.sidious.supportsystem.Repository;
010 import dk.deepthought.sidious.supportsystem.State;
011 import dk.deepthought.sidious.supportsystem.Step;
012 import dk.deepthought.sidious.supportsystem.SuperLinkID;
013 
014 /**
015  * This is the base class for representing a Rule. It is designed to be extended
016  * by classes defining rules of the system.
017  <p>
018  * Rules can be goal-oriented and work towards a specific goal. They can also
019  * represent a conflict or an expense.
020  
021  @author Deepthought
022  
023  */
024 public abstract class Rule {
025 
026     /**
027      * The ID of the originating <code>PlanRequester</code>.
028      */
029     private SuperLinkID parentID;
030 
031     /**
032      * Method returns a collection of immediate goals.
033      <p>
034      * If there are no immediate goals, an empty collection is returned.
035      
036      @return the goals of this rule
037      */
038     public abstract Collection<Goal> getGoals();
039 
040     /**
041      * Method returns the calculated desire associated with the change from
042      <code>currentState</code> to <code>newState</code>.
043      <p>
044      * The calculated desire must evaluate to [0,1], where 0 represents no
045      * desire for changing state, and 1 represents maximum desire for change.
046      <p>
047      * Some rules are allowed to evaluate to values (much) larger than 1. This
048      * exception is only allowed if the outcome of <b>not</b> respecting the
049      * rule is fatal.
050      
051      @param currentState
052      *            the current state
053      @param newState
054      *            the new state
055      @param step
056      *            the step
057      
058      @return the calculated desire
059      */
060     public abstract double desire(State currentState, State newState, Step step);
061 
062     /**
063      * Gets the explanation/reasoning from a rule.
064      <p>
065      * Override this method if a more detailed explanation is needed.
066      @return The explanation.
067      */
068     public String getExplanation() {
069         return getClass().getSimpleName();
070     }
071 
072     /**
073      * Gets the parent id of this rule.
074      
075      @return the parentID
076      */
077     public SuperLinkID getParentID() {
078         return parentID;
079     }
080 
081     /**
082      * Sets the parent id for this rule.
083      
084      @param parentID
085      *            the parentID to set
086      */
087     public void setParentID(SuperLinkID parentID) {
088         this.parentID = parentID;
089     }
090     
091     /**
092      * Method returns the value of the input <code>sensorID</code> in the
093      * input <code>state</code>. If the sensor isn't represented in the
094      * state, 0 is returned.
095      
096      @param state
097      *            the state
098      @param sensorID
099      *            the id
100      @return the value of the sensor
101      */
102     protected double getSensorValue(State state, SuperLinkID sensorID) {
103         if (state instanceof ClimaticState) {
104             ClimaticState currentClima = (ClimaticStatestate;
105             for (SensorInput input : currentClima.getSensors()) {
106                 if (input.getID().equals(sensorID)) {
107                     return input.getValue();
108                 }
109             }
110         }
111         return 0;
112     }
113 
114     /**
115      * Method returns the setting of the input adjustable.
116      
117      @param adjustableID
118      *            id of the adjustable
119      @return the setting
120      */
121     protected double getAdjustableSettingFromParent(SuperLinkID adjustableID) {
122         //FIXME WHY is this method not static?
123         //Check use and visibility
124         return Repository.getBlackboard().getAdjustableSetting(parentID,
125                 adjustableID);
126     }
127 
128     /**
129      * Returns the setting of an adjustable contained in the <code>step</code>
130      * identified by the <code>id</code>.
131      
132      @param step
133      *            the step
134      @param id
135      *            the id
136      @return the setting
137      */
138     protected double getAdjustableSetting(Step step, SuperLinkID id) {
139         //FIXME WHY is this method not static? 
140         //Check use and visibility
141         if (step == null) {
142             return 0;
143         }
144         Collection<Adjustable> adjustables = step.getAdjustables();
145         for (Adjustable adjustable : adjustables) {
146             if (adjustable.getID().equals(id)) {
147                 return adjustable.getSetting();
148             }
149         }
150         return 0;
151     }
152     
153 }