View Javadoc

1   /*
2   * The contents of this file are subject to the BT "ZEUS" Open Source 
3   * Licence (L77741), Version 1.0 (the "Licence"); you may not use this file 
4   * except in compliance with the Licence. You may obtain a copy of the Licence
5   * from $ZEUS_INSTALL/licence.html or alternatively from
6   * http://www.labs.bt.com/projects/agents/zeus/licence.htm
7   * 
8   * Except as stated in Clause 7 of the Licence, software distributed under the
9   * Licence is distributed WITHOUT WARRANTY OF ANY KIND, either express or 
10  * implied. See the Licence for the specific language governing rights and 
11  * limitations under the Licence.
12  * 
13  * The Original Code is within the package zeus.*.
14  * The Initial Developer of the Original Code is British Telecommunications
15  * public limited company, whose registered office is at 81 Newgate Street, 
16  * London, EC1A 7AJ, England. Portions created by British Telecommunications 
17  * public limited company are Copyright 1996-9. All Rights Reserved.
18  * 
19  * THIS NOTICE MUST BE INCLUDED ON ANY COPY OF THIS FILE
20  */
21  
22  
23  
24  package zeus.actors;
25  
26  import java.util.*;
27  import java.awt.Color;
28  import zeus.util.*;
29  import zeus.concepts.*;
30  import zeus.concepts.fn.*;
31  import zeus.actors.rtn.*;
32  import zeus.actors.rtn.util.DelegationStruct;
33  
34  /***
35      * PlanRecord is used to manage the execution of a (primitive, mutable or infered) task. 
36      * The field task is the primitive task being executed, the field thread is the ZeusTask 
37      * that is actually being run
38      */
39  public class PlanRecord implements SuppliedRequester {
40     public static final int FREE      = 0;
41     public static final int TEMP      = 1;
42     public static final int TENTATIVE = 2;
43     public static final int FIRM      = 3;
44     public static final int RUNNING   = 4;
45     public static final int FAILED    = 5;
46     public static final int COMPLETED = 6;
47     public static final int JEOPARDY  = 7;
48     public static final int AGREEMENT = 8;
49  
50     protected static final boolean BOOKED = true;
51  
52     public static final Color[] color = {
53        Color.lightGray,
54        Color.orange,
55        Color.yellow,
56        Color.cyan,
57        Color.green,
58        Color.red,
59        Color.white,
60        Color.magenta,
61        Color.blue
62     };
63  
64     public static final String[] state_string = {
65        "Free",
66        "Temporary",
67        "Tentative",
68        "Firm",
69        "Running",
70        "Failed",
71        "Completed",
72        "Jeopardy",
73        "Service-Agreement"
74     };
75  
76     protected Planner planner;
77     protected int state = TEMP;
78     protected PlanRecord parent;
79     protected String id;
80     protected Goal goal;
81     protected PrimitiveTask task;
82     protected int proc;
83     protected int start_time;
84     protected int lstart_time;
85     protected int end_time;
86     protected double cost;
87     protected ZeusTask thread = null;
88     protected String diagnostic = null;
89     protected String key = null;
90     protected boolean is_disposed = false;
91  
92     protected ConsumedDb consumedDb = null;
93     protected ProducedDb producedDb = null;
94     protected int reconfirm_count = 0;
95  
96     protected Vector other_tasks = null;
97     protected Vector path = null;
98  
99     // additional info for handling continuous goals and their enactments
100    protected PlanRecord original = null;
101    protected int noAllowedInvocations = 1;
102    protected int noAvailableItems = 0;
103    protected boolean[] slots = null;
104    protected Vector    images = null;
105 
106 
107    public PlanRecord () {
108     ;
109     }
110 
111 
112    protected void init(Planner planner, String key, PlanRecord parent,
113                        Goal goal, PrimitiveTask task, int proc, int start,
114                        int end) {
115 
116       Assert.notNull(key);
117       Assert.notNull(goal);
118       Assert.notNull(task);
119       Assert.notFalse(start >= 0);
120       Assert.notFalse(end >= 0);
121       Assert.notFalse(proc >= 0);
122 
123       this.planner = planner;
124       this.key = key;
125       this.parent = parent;
126       this.id = planner.getAgentContext().newId("PlanRecord");
127       this.goal = goal;
128       this.task = task;
129       this.start_time = start;
130       this.lstart_time = start;
131       this.end_time = end;
132       this.proc = proc;
133       this.cost = task.getCost();
134 
135       if ( (noAvailableItems = goal.getFact().getNumber()) == 0 ) {
136          Core.USER_ERROR("Integer expected in goal.fact.no field." +
137          "\nEnsure \"no\" constraints are defined in all task specifications");
138 
139          // ERROR FIX
140          noAvailableItems = 1;
141       }
142       task.preprocess();
143       consumedDb = new ConsumedDb(this,task);
144       producedDb = new ProducedDb(this,task);
145 
146       Core.DEBUG(3,"PlanRecord created: " + this);
147    }
148 
149    public PlanRecord(Planner planner, String key, PlanRecord parent,
150                      Goal goal, PrimitiveTask task, int proc, int start,
151                      int end) {
152 
153       init(planner, key, parent, goal, task, proc, start, end);
154       producedDb.add(task.getActiveEffectPos(), parent, noAvailableItems,
155                      goal.getId(),!(goal.getFact().isReadOnly()));
156 
157       if ( parent != null )
158          parent.updateCost(cost);
159 
160       planner.add(this);
161       planner.notifyMonitors(this,Planner.CREATE);
162    }
163 
164    protected PlanRecord(Planner planner, PlanRecord original, String key,
165                         PlanRecord parent, Goal goal, PrimitiveTask task,
166                         int proc, int start, int end) {
167 
168       Assert.notNull(original);
169       Assert.notFalse(goal.whichType() == Goal.DISCRETE);
170       init(planner, key, parent, goal, task, proc, start, end);
171       this.original = original;
172 
173       planner.add(this);
174       planner.notifyMonitors(this,Planner.CREATE);
175    }
176 
177    public String        getId()              { return id; }
178    public int           getProc()            { return proc; }
179    public int           getState()           { return state; }
180    public int           getStartTime()       { return start_time; }
181    public int           getLatestStartTime() { return lstart_time; }
182    public int           getEndTime()         { return end_time; }
183    public PrimitiveTask getTask()            { return task; }
184    public Goal          getGoal()            { return goal; }
185    public PlanRecord    getParent()          { return parent; }
186    public String        getKey()             { return key; }
187    public double        getCost()            { return cost; }
188    public ConsumedDb    getConsumedDb()      { return consumedDb; }
189    public ProducedDb    getProducedDb()      { return producedDb; }
190    public AgentContext  getAgentContext()    { return planner.getAgentContext(); }
191    public SuppliedDb    getSuppliedDb()      { return goal.getSuppliedDb(); }
192 
193    public int anySideEffect(Fact desc, PlanRecord rec,
194                             Object precond, int required) {
195 
196       boolean status = isDiscrete() && (state == FIRM || state == RUNNING);
197       status |= (getRoot() == rec.getRoot());
198 
199       if ( !status ) return required;
200 
201       Fact[] produced = task.getPostconditions();
202       Bindings b = new Bindings(planner.getAgentContext().whoami());
203       for(int i = 0; required > 0 && i < produced.length; i++, b.clear()) {
204          if ( produced[i].unifiesWith(desc,b) )
205             required = producedDb.anySideEffect(i,rec,precond,required);
206       }
207       return required;
208    }
209 
210    public void setAlternativeTasks(Vector Tasks) {
211       this.other_tasks = Tasks;
212    }
213    
214    
215    public void setPath(Vector path) {
216       this.path = path;
217    }
218    
219    
220    public Vector getChildPath() {
221       Vector child_path = Misc.copyVector(path);
222       child_path.addElement(goal.getFact());
223       return child_path;
224    }
225 
226 
227    public PlanRecord[] getChildren() { 
228       return consumedDb.getChildren();
229    }
230    
231    
232    public boolean hasAtMostOneParent(PlanRecord parent, String key) {
233       return producedDb.hasAtMostOneParent(parent,key);
234    }
235    public DataRec getDatarec(int precond_position) {
236       return consumedDb.getDatarec(precond_position);
237    }
238    public int getConsumedPosition(String goal_id) {
239       return consumedDb.getPosition(goal_id);
240    }
241    
242    
243    public boolean isPreconditionConsumed(int precond_position) {
244       Fact precond = task.getPrecondition(precond_position);
245       return !precond.isReadOnly();
246    }
247    
248    
249    public int noRequiredItems(int precond_position) {
250       return consumedDb.requiredItems(precond_position);
251    }
252    
253    
254    public int getAmountUsed(int precond_position) {
255       return consumedDb.amountUsed(precond_position);
256    }
257    
258    
259    public boolean setSupplier(int precond_position, int amount,
260                               SuppliedItem item) {
261 
262       String Id = planner.getAgentContext().newId("used");
263       boolean consumed = isPreconditionConsumed(precond_position);
264       boolean b = item.reserve(Id,start_time,consumed,
265          amount,planner.getAgentContext().whoami(), goal.getId(),key);
266       if ( b ) consumedDb.add(precond_position,Id,amount);
267       return b;
268    }
269 
270    public void chainPrecondition(PlanRecord child, int effect_position,
271                                  int amount, int precond_position) {
272       consumedDb.add(precond_position,child,effect_position,amount);
273    }
274    
275    
276    public void preconditionExists(PlanRecord child, int effect_position,
277                                   int amount, int precond_position) {
278       consumedDb.factExists(precond_position,child,effect_position,amount);
279    }
280    
281    
282    public void preconditionExists(String goal_id) {
283       consumedDb.factExists(goal_id);
284    }
285    
286    
287    public void replacePrecondition(String goal_id, PlanRecord child,
288                                    int effect_position, int amount) {
289       consumedDb.replace(goal_id,child,effect_position,amount);
290    }
291    
292    
293    public void breakEffectChain(int effect_position, PlanRecord rec,
294                                 int precond_position, int amount) {
295       producedDb.remove(effect_position,rec,precond_position,amount);
296       if ( parent == rec && !producedDb.references(parent) ) {
297          parent = producedDb.firstParent();
298          if ( parent != null ) {
299             int first_position = producedDb.firstPosition(parent);
300             task.setActiveEffect(first_position);
301             goal.setFact(task.getActiveEffect());
302             setKey(parent.getKey());
303          }
304          else {
305 //REM: need to check this later
306             String other_key = producedDb.firstKey();
307             if ( other_key != null )
308                setKey(other_key);
309          }
310       }
311    }
312 
313    public Goal recreateSubgoal(Goal g) {
314       int position = consumedDb.getPosition(g.getId());
315       Fact x = consumedDb.remove(g.getId());
316       Goal g1 = createSubgoal(x,position);
317       double t = planner.getAgentContext().now() +
318                  planner.getAgentContext().getReplanPeriod();
319       g1.setConfirmTime(new Time(t));
320 
321       g1.setSuppliedDb(this.goal.getSuppliedDb());
322 
323       setState(JEOPARDY);
324       return g1;
325    }
326 
327    public void reconfirm() {
328       Assert.notFalse(state == JEOPARDY);
329       Core.DEBUG(2,"Decrementing reconfirm from: " + reconfirm_count);
330       if ( --reconfirm_count == 0 )
331          setState(FIRM);
332    }
333 
334    public void setKey(String nkey) {
335       Core.DEBUG(3,"PlanRecord: " + this + "\n\tsetKey: " + nkey);
336       if ( parent == null || nkey.equals(parent.getKey()) ) {
337          consumedDb.update(nkey,this.key);
338          this.key = nkey;
339 
340          PlanRecord[] children = consumedDb.getChildren();
341          for(int i = 0; i < children.length; i++ )
342             children[i].setKey(nkey);
343       }
344    }
345 
346    public boolean isDiscrete() {
347       return goal.whichType() == Goal.DISCRETE;
348    }
349    public boolean isContinuous() {
350       return goal.whichType() == Goal.CONTINUOUS;
351    }
352    public boolean hasMoreEnactments() {
353       Assert.notFalse(goal.whichType() == Goal.CONTINUOUS);
354       return noAvailableItems > 0;
355    }
356    public boolean hasEnoughResources() {
357       return consumedDb.hasEnoughResources();
358    }
359 
360    public void updateCost(double value) {
361 // System.err.print(this + "\n\tUpdating cost from " + cost);
362       this.cost += value;
363 // System.err.println(" to " + cost);
364       if ( parent != null ) parent.updateCost(value);
365    }
366 
367    public boolean applyConstraints(Bindings bindings) {
368       if ( !task.applyConstraints(bindings) ) return false;
369       return producedDb.constrain(bindings);
370    }
371 
372    public Bindings getBindings() {
373       Bindings b = new Bindings(planner.getAgentContext().whoami());
374       Fact f1 = goal.getFact();
375       Fact f2 = task.getActiveEffect();
376       Assert.notFalse( f2.unifiesWith(f1,b) );
377       return b;
378    }
379 
380    public boolean isOnCell(int proc,int t) {
381       return this.proc == proc && t >= start_time && t < end_time;
382    }
383 
384    protected void vacatingPosition(int proc, int start, int end) {
385       Assert.notFalse(goal.whichType() == Goal.CONTINUOUS);
386       Assert.notFalse(proc == this.proc);
387 
388       for(int i = start - start_time; i < end - start_time; i++ )
389          slots[i] = !BOOKED;
390 
391       for(int i = start; i < end; i++ )
392          planner.assignCell(proc,i,this);
393    }
394    
395    
396    protected void originalDisposed() {
397       Assert.notNull(original);
398       original = null;
399    }
400    
401    
402    public void reassign(int pc, int st) {
403       if ( original != null ) 
404          original.vacatingPosition(proc,start_time,end_time);
405       else 
406          planner.freeCells(proc,start_time,end_time);
407 
408       proc = pc;
409       start_time = st;
410       end_time = st + task.getTime();
411       consumedDb.newStartTime(start_time);
412    }
413    
414    
415    public void incrementTime(int t) {
416       // we want to shift from the [now] to the [now+1] position
417       planner.freeCell(proc,end_time-1);
418       end_time = t+1;
419    }
420       
421       
422    public String diagnostic() {
423       return diagnostic;
424    }
425 
426 
427     /*** 
428        * mapPreToPost is used to map precondition variables that are 
429        * supposed to be copied to post conditions
430        * synchronised?
431        *@author Simon Thompson
432        *@since 1.2
433         */
434   public  Fact [][] mapPreToPost(Fact [][] input, Fact[] exp_out) { 
435     // assume one out for now. 
436     Core.DEBUG (1, "in mapPreToPost"); 
437     AgentContext cont = this.getAgentContext(); 
438     TaskDb tdb = cont.getTaskDb(); 
439     String taskName = task.getName(); 
440     Task retTask = tdb.getTask (taskName); 
441     
442     Fact [] retPre = retTask.getPreconditions(); 
443     Fact [] retPost = retTask.getPostconditions(); 
444       
445     debug("\nTask from DB = " + retTask.toString()); 
446     
447     debug("\nThis task = " + task.toString()); 
448     
449     Fact [][] output = new Fact [exp_out.length][1];
450     debug(String.valueOf(input.length));
451     for (int count = 0; count<input.length; count++) { 
452         // for all input facts 
453         debug(String.valueOf(exp_out.length)); 
454         for (int count2 = 0; count2 < exp_out.length; count2++) { 
455             // for all output facts
456             // primitiveTask post conditions... effects and preconditions = 
457             output[count2][0] = exp_out[count2];
458             // build a map of copy instructions from the task description
459             String [] map = retPost[count2].buildMap(retPre[count]);
460             // apply that map to the pre and post conditions for this instantiation
461             output[count2][0].doMap(input[count][0],map); 
462             debug("in = " + input[count][0] + " out = " +output[count2][0]); 
463                     
464                 }
465         }
466     return output; 
467     
468   }
469   
470   /*** 
471     bind the any variables in the task cost and time to their pre & postcondition 
472     values at run time 
473     
474     */
475     public void mapCostAndTime() {
476         AgentContext cont = this.getAgentContext(); 
477         TaskDb tdb = cont.getTaskDb(); 
478         String taskName = task.getName();
479         Task retTask = tdb.getTask (taskName); 
480         Fact [] retPost = retTask.getPostconditions(); 
481         Fact [] post = task.getPostconditions(); 
482         Fact [] retPre = retTask.getPreconditions(); 
483         Fact [] pre = task.getPreconditions(); 
484         ValueFunction time = task.getTimeFn(); 
485         ValueFunction cost = task.getCostFn(); 
486         for (int i = 0; i<retPost.length; i++) { 
487             map (time, retPost[i], post[i]);
488             map  (cost, retPost[i], post[i]); 
489         }
490         for (int i = 0; i<retPre.length; i++) { 
491             map (time, retPre[i], pre[i]); 
492             map (cost,retPre[i], pre[i]);
493         }
494             
495 
496     }
497 
498 
499     public void map (ValueFunction val, Fact lhs, Fact rhs) { 
500         debug ("val = " + val.toString() + "\nlhs = " + lhs.toString() + "\nrhs = " + rhs.toString()); 
501     }
502     
503     
504  public boolean exec() {
505      diagnostic = null;
506      PrimitiveTask task_image = new PrimitiveTask(task);
507   
508 /***
509       Fact fact = goal_image.getFact();
510       Fact f2 = task_image.getActiveEffect();
511       es.ok = es.ok && f2.unifiesWith(fact,b)
512 */
513         
514       if ( goal.whichType() != Goal.DISCRETE || thread != null )
515          return false;
516 
517       if ( !consumedDb.hasEnoughResources() ) {
518          setState(FAILED);
519          diagnostic = "1: Cannot exec - inadequate resources";
520          Core.DEBUG(2,diagnostic);
521          return true;
522       }
523       try {
524          String name = task.getName();
525 
526          /* For experiment only */
527          if ( name.startsWith("GenTask") )
528             name = "GenTask";
529          /* Experiment ends */
530        //  task.relaxNumberFields();   
531          
532          Class c = Class.forName(name);
533          thread = (ZeusTask) c.newInstance();
534          Fact[][] input = consumedDb.getInputData();
535          consumedDb.consumeResources();
536          System.out.println(task.pprint());
537          thread.setInputArgs(input);
538          /*** 
539             everything else is being set from the primitiveTask, but
540             this is not right... I think that the output arguments need to
541             be mapped from the inputArgs at this point
542             */
543             
544          thread.setExpectedOutputArgs(task.getOriginalPostconditions());
545          
546          Fact[]  exp_input =  task.getPreconditions();
547          thread.setExpectedInputArgs(exp_input);
548 
549          thread.setMedia(goal.getTargetMedia());
550          thread.setContext(getAgentContext());
551          Fact [] exp_out = task.getOriginalPostconditions(); 
552          Fact [][] act_out = null; 
553          // deal with 0 preconditions
554          if (input.length>0) { 
555             act_out = mapPreToPost (input,exp_out);// added 1.2.1
556          }
557             else {
558                 act_out = new Fact [exp_out.length][1];
559                 for (int i = 0; i<exp_out.length;i++) { 
560                     act_out[i][0] = exp_out[i]; }
561             }
562          mapCostAndTime(); // addesd 1.2.1
563          Bindings b = new Bindings(planner.getAgentContext().whoami());
564          task.resolve(b);
565         
566          thread.setOutputArgs (act_out); 
567          for (int count = 0;  count<act_out.length; count ++ ) { 
568             exp_out[count]= act_out[count][0]; 
569          }
570          thread.setExpectedOutputArgs(exp_out); 
571        // was commented out         
572             Fact [][] user_out = new Fact [task.getOriginalPostconditions().length][1];
573             Fact[][] output = new Fact[task.getOriginalPostconditions().length][1];
574             
575             for (int count = 0; count<user_out.length; count++ ) { 
576                 user_out[count][0] = exp_out[count];
577             }
578  
579             for(int i = 0; i < user_out.length; i++ ) {
580                 debug ("user_out[" + String.valueOf(i) + "] = " + user_out[i].toString()); 
581                output[i] = user_out[i];
582          
583                }
584 
585          /***   int j = user_out.length;
586             for(int i = 0; i < exp_input.length; i++ )
587                if ( exp_input[i].isReplaced() )
588                   output[j++] = input[i]; */
589        
590          task.relaxNumberFields();
591          thread.start(); // 21/06/01
592      //    producedDb.allocatePostconditions(output);
593 
594        //thread.start();
595          setState(RUNNING);
596          diagnostic = "Running started ... ";
597          Core.DEBUG(2,diagnostic);
598       }
599       
600       catch(ClassNotFoundException e) {
601          setState(FAILED);
602          diagnostic = "2: Cannot exec - ClassNotFoundException";
603          Core.DEBUG(2,diagnostic);
604       }
605       catch(IllegalAccessException e) {
606          setState(FAILED);
607          diagnostic = "3: Cannot exec - IllegalAccessException";
608          Core.DEBUG(2,diagnostic);
609       }
610       catch(InstantiationException e) {
611          setState(FAILED);
612          diagnostic = "4: Cannot exec - InstantiationException";
613          Core.DEBUG(2,diagnostic);
614       }
615       return true;
616    }
617 
618  
619 
620     
621   
622    public boolean overRun() {
623       ResourceDb resDb = getAgentContext().getResourceDb(); 
624       if ( thread.isFinished() ) {
625          Fact[][] user_out = thread.getOutputArgs();
626 
627          if ( user_out != null && user_out.length > 0 ) {
628             Fact[][] output = thread.outputArgs; 
629 	    //    Fact[][] output = new Fact[task.countPostconditions()][];
630             Fact[][] input = thread.getInputArgs();
631             Fact[]   exp_input = thread.getExpectedInputArgs();
632 
633            // for(int i = 0; i < user_out.length; i++ )
634              // output[i] = user_out[i];
635 
636               int j = user_out.length;
637               for(int i = 0; i < exp_input.length; i++ )
638               if ( exp_input[i].isReplaced() )
639                       resDb.add(input[i]); 
640                       //output[j++] = input[i]; // surely added to resdb!
641 
642             // readded 21/6/01
643             if (output!= null) 
644                 producedDb.allocatePostconditions(output);
645             
646             setState(COMPLETED);
647             return false;
648          }
649          else {
650             setState(FAILED);
651             diagnostic = "5: Failed - task execution did not produce output";
652             return false;
653          }
654       }
655       double t = planner.getAgentContext().now();
656       // 1.3 change >= 
657       if ( t >= end_time ) {
658          if ( t < goal.getEndTime() &&
659               planner.incrementProcessorTime(this,(int)t) ) {
660             // we have some time to spare and a free proc to use
661             return false;
662          }
663          setState(FAILED);
664          diagnostic = "5: Failed - overrun allocated time: " +
665                       t + " > " + end_time;
666          thread.abort();
667          return true;
668       }
669       return false;
670    }
671 
672 
673    protected void setState(int newState, PlanRecord parent) {
674       /*
675       This guards against cases where a foster parent tries to
676       change the state of a child (cf. side-effects).
677       */
678       if ( parent == this.parent )
679          setState(newState);
680    }
681    
682    
683    public void setState(int newState) {
684       Assert.notFalse(newState >= TEMP && newState <= AGREEMENT);
685 
686       Core.DEBUG(3,"Setting state for rec " + id + " from " +
687                    state_string[state] + " to " + state_string[newState]);
688       state = newState;
689       planner.notifyMonitors(this,Planner.STATE_CHANGE);
690 
691       PlanRecord[] children;
692       switch( state ) {
693          case TEMP:
694          case TENTATIVE:
695               children = getChildren();
696               for(int i = 0; i < children.length; i++ )
697                  children[i].setState(newState,this);
698               break;
699 
700          case FIRM:
701               Core.DEBUG(3,this);
702               Core.DEBUG(3,producedDb);
703               Core.DEBUG(3,consumedDb);
704 
705               goal.setSuppliedDb(null);
706               if ( goal.whichType() == Goal.CONTINUOUS ) {
707                  setState(AGREEMENT);
708                  return;
709               }
710               children = getChildren();
711               for(int i = 0; i < children.length; i++ ) 
712                  children[i].setState(newState,this);
713               break;
714 
715          case AGREEMENT:
716               goal.setSuppliedDb(null);
717               Assert.notFalse(goal.whichType() == Goal.CONTINUOUS);
718               if ( slots == null ) {
719                  noAllowedInvocations = goal.getInvocations();
720                  slots = new boolean[end_time-start_time];
721                  for(int i = 0; i < slots.length; i++ )
722                     slots[i] = !BOOKED;
723                  images = new Vector();
724               }
725               children = getChildren();
726               for(int i = 0; i < children.length; i++ )
727                  children[i].setState(newState,this);
728               break;
729 
730          case RUNNING:
731               break;
732 
733          case COMPLETED:
734               break;
735 
736          case FAILED:
737               dispose(parent,key);
738               producedDb.notifyFailed(other_tasks,path); 
739               break;
740 
741          case JEOPARDY:
742               reconfirm_count++;
743               break;
744 
745          default:
746               break;
747       }
748    }
749    
750    
751    public void softFail(PlannerQueryStruct struct, int mode) {
752       Core.DEBUG(2,"softFail..." + struct);
753 
754       if ( mode == Planner.REPLAN ) {
755          state = FAILED;
756          planner.notifyMonitors(this,Planner.STATE_CHANGE);
757       }
758 
759       Goal g;
760       Vector subgoals = descendantSubgoals();
761       subgoals.addElement(this.goal.getId());
762       for(int i = 0; i < struct.external.size(); i++ ) {
763          g = (Goal)struct.external.elementAt(i);
764          if ( subgoals.contains(g.getId()) )
765             struct.external.removeElementAt(i--);
766       }
767       dispose(parent,key);
768       if ( mode == Planner.REPLAN ) {
769          planner.clear_bind(struct.goals);
770          for(int i = 0; i < struct.goals.size(); i++ ) {
771             g = (Goal)struct.goals.elementAt(i);
772             if ( subgoals.contains(g.getId()) )
773                struct.goals.removeElementAt(i--);
774          }
775       }
776       producedDb.softNotifyFailed(other_tasks,path,struct,mode);
777    }
778 
779 
780    public Vector descendantSubgoals() {
781       Vector subgoals = consumedDb.currentSubgoals();
782       PlanRecord[] children = consumedDb.getChildren();
783       Vector sub;
784       for(int i = 0; i < children.length; i++ ) {
785          sub = children[i].descendantSubgoals();
786          subgoals = Misc.union(subgoals,sub);
787       }
788       return subgoals;
789    }
790 
791 
792    public int latestConfirmTime() {
793       int lct = start_time;
794 
795       PlanRecord[] children = consumedDb.getChildren();
796       for(int i = 0; i < children.length; i++ )
797          lct = Math.min(lct,children[i].latestConfirmTime());
798       return lct;
799    }
800 
801 
802    public void dispose() {
803       dispose(parent,key,goal.getSuppliedDb());
804    }
805    
806    
807    public void dispose(PlanRecord parent, String key) {
808       dispose(parent,key,goal.getSuppliedDb());
809    }
810 
811    protected void dispose(PlanRecord aParent, String aKey,
812                           SuppliedDb db) {
813       if ( is_disposed ) return;
814 
815       Core.DEBUG(3,"Dispose rec " + id + "-" + goal.getFactType() +
816                    ":  " + state_string[state]);
817 
818       PlanRecord rec;
819       PlanRecord[] children;
820       switch(state) {
821          case TEMP:
822          case TENTATIVE:
823          case FIRM:
824          case RUNNING:
825          case JEOPARDY:
826 /*
827          NOTE: for sla enactments, when disposing a record which is
828          FIRM,RUNNING,JEOPARDY  we need to return the consumed_db data back
829          to the original
830 */
831               if ( producedDb.hasAtMostOneParent(aParent,aKey) ) {
832                  Core.DEBUG(3,"rec " + id + " hasAtMostOneParent");
833                  // we can safely dispose this record
834                  planner.freeCells(proc,start_time,end_time);
835                  if ( thread != null ) thread.abort();
836                  thread = null;
837                  children = consumedDb.getChildren();
838                  for(int i = 0; i < children.length; i++ )
839                     children[i].dispose(this,key);
840                  consumedDb.releaseResources(db);
841                  Core.DEBUG(3,"Calling planner.del: " + this);
842                  planner.del(this);
843                  is_disposed = true;
844                  planner.notifyMonitors(this,Planner.DISPOSE);
845               }
846               break;
847 
848          case AGREEMENT:
849               for(int i = 0; images != null && i < images.size(); i++ ) {
850                  rec = (PlanRecord)images.elementAt(i);
851                  rec.originalDisposed();
852               }
853 
854          case FAILED:
855          case COMPLETED:
856               // we must dispose this record
857               if ( thread != null ) thread.abort();
858               thread = null;
859 
860               if ( goal.whichType() == Goal.CONTINUOUS ) {
861                  for(int i = 0; i < slots.length; i++ )
862                     if ( slots[i] != BOOKED )
863                        planner.freeCell(proc,i+start_time);
864               }
865               else {
866                  planner.freeCells(proc,start_time,end_time);
867               }
868 
869               children = consumedDb.getChildren();
870               for(int i = 0; i < children.length; i++ )
871                  children[i].dispose(this,key);
872               consumedDb.releaseResources(db);
873               planner.del(this);
874               is_disposed = true;
875               planner.notifyMonitors(this,Planner.DISPOSE);
876               break;
877 
878          default:
879               Assert.notNull(null);
880       }
881    }
882 
883 
884    public boolean hasAncestor(PlanRecord ancestor) {
885       PlanRecord father = this;
886       while( father != null ) {
887          if ( father == ancestor )
888             return true;
889          father = father.getParent();
890       }
891       return false;
892    }
893    
894    
895    public PlanRecord getRoot() {
896       PlanRecord root = this;
897       while( root.getParent() != null )
898          root = root.getParent();
899       return root;
900    }
901 
902    public void reallocateResource(int precond_position, int amount) {
903       reallocateResource(precond_position,amount,null,null);
904    }
905    
906    
907    public void reallocateResource(int precond_position, PlanRecord child,
908                                   int effect_position, int amount,
909                                   Vector Tasks, Vector path) {
910       consumedDb.remove(precond_position,child,effect_position,amount);
911       reallocateResource(precond_position,amount,Tasks,path);
912    }
913    
914    
915    public void reallocateResource(int precond_position, int amount,
916                                   Vector Tasks, Vector Path) {
917       ResourceDb db = planner.getAgentContext().ResourceDb();
918       Goal g;
919 
920       Core.DEBUG(3,"Attempting reallocation...");
921 
922       SuppliedDb given = this.goal.getSuppliedDb();
923       if ( given != null )
924          amount = given.allocateResource(this,precond_position,amount);
925 
926       if ( amount == 0 ) return;
927 
928       if ( (g = db.allocateResource(this,precond_position,amount)) == null )
929          return;
930 
931       diagnostic = "Required resource unavailable - replanning";
932       setState(JEOPARDY);
933 
934       double t = planner.getAgentContext().now() +
935                  planner.getAgentContext().getReplanPeriod();
936       g.setConfirmTime(new Time(t));
937 
938       Core.DEBUG(3,"Reallocation failed... internal replanning");
939 
940       if ( path == null )
941          path = Misc.copyVector(this.path);
942 
943       PlannerQueryStruct struct = new PlannerQueryStruct(g);
944       struct.internal.addElement(this);
945       planner.schedule(key,this,path,g,Tasks,struct,Planner.EXPAND);
946 
947       if ( !struct.external.isEmpty() ) {
948          Core.DEBUG(3,"Reallocation failed... external replanning");
949          planner.index(struct);
950          planner.getAgentContext().Engine().replan(struct,key);
951       }
952       else if ( !struct.internal.isEmpty() )
953          reconfirm();
954                                   }
955 
956    public void raiseException(int effect_position, String exception_key,
957                               int amount) {
958 
959       // Assert.notFalse(exception_key.equals(key));
960       // g must be the same as this.goal
961 
962       Goal g = new Goal(goal);
963 
964       g.setId(planner.getAgentContext().newId("subgoal"));
965       g.setImage(goal.getId());
966 
967       Fact needed = task.getPostcondition(effect_position);
968       needed.setNumber(amount);
969       g.setFact(needed);
970       g.setDesiredBy(planner.getAgentContext().whoami());
971       double t = planner.getAgentContext().now() +
972                  planner.getAgentContext().getReplanPeriod();
973       g.setConfirmTime(new Time(t));
974 
975       Core.DEBUG(3,"Top goal... internal replanning");
976 
977       PlannerQueryStruct struct = new PlannerQueryStruct(g);
978       planner.schedule(key,null,path,g,other_tasks,struct,Planner.EXPAND);
979       if ( !struct.internal.isEmpty() ) {
980          if ( !struct.external.isEmpty() ) {
981             Core.DEBUG(3,"Top goal... external replanning");
982             planner.index(struct);
983             planner.getAgentContext().Engine().replan(struct,key);
984          }
985          else 
986             planner.book(FIRM,g,struct.internal);
987       }
988       else {
989          Vector goals = new Vector();
990          goals.addElement(goal);
991          DelegationStruct ds = new DelegationStruct(planner.getAgentContext().whoami(),
992                                    "failure",exception_key,goals);
993          planner.getAgentContext().Engine().add(ds);
994       }
995    }
996 
997 
998    public void softReallocateResource(int precond_position, PlanRecord child,
999                                       int effect_position, int amount,
1000                                       Vector Tasks, Vector path,
1001                                       PlannerQueryStruct struct, int mode) {
1002       consumedDb.remove(precond_position,child,effect_position,amount);
1003       softReallocateResource(precond_position,amount,Tasks,path,struct,mode);
1004    }
1005    
1006    
1007    public void softReallocateResource(int precond_position, int amount,
1008                                       Vector Tasks, Vector Path,
1009                                       PlannerQueryStruct struct, int mode) {
1010 
1011       ResourceDb db = planner.getAgentContext().ResourceDb();
1012       Goal g;
1013 
1014       if ( path == null )
1015          path = Misc.copyVector(this.path);
1016 
1017       Core.DEBUG(3,"Attempting soft reallocation...");
1018 
1019       SuppliedDb given = this.goal.getSuppliedDb();
1020       if ( given != null )
1021          amount = given.allocateResource(this,precond_position,amount);
1022 
1023       if ( amount == 0 ) return;
1024 
1025       if ( (g = db.allocateResource(this,precond_position,amount)) == null )
1026          return;
1027 
1028       diagnostic = "Required resource unavailable - replanning";
1029       if ( mode == Planner.REPLAN ) { 
1030          struct.goals.addElement(g);
1031          planner.index(struct);
1032          setState(JEOPARDY);
1033          double t = planner.getAgentContext().now() +
1034                     planner.getAgentContext().getReplanPeriod();
1035          g.setConfirmTime(new Time(t));
1036       }
1037       else {
1038         g.setConfirmTime(this.goal.getConfirmTime());
1039       }
1040 
1041       Core.DEBUG(3,"Soft reallocation failed... internal replanning");
1042 
1043       if ( !struct.internal.contains(this) )
1044          struct.internal.addElement(this);
1045 
1046       planner.schedule(key,this,path,g,Tasks,struct,Planner.EXPAND);
1047    }
1048 
1049 
1050    public void softRaiseException(int effect_position, String exception_key,
1051                                   int amount, PlannerQueryStruct struct,
1052                                   int mode) {
1053 
1054       // Assert.notFalse(exception_key.equals(key));
1055       // g must be the same as this.goal
1056 
1057       Fact needed = task.getPostcondition(effect_position);
1058       needed.setNumber(amount);
1059   
1060       Goal g;
1061       if ( mode == Planner.REPLAN ) {
1062          g = new Goal(goal);
1063 
1064          g.setId(planner.getAgentContext().newId("subgoal"));
1065          g.setImage(goal.getId());
1066          g.setDesiredBy(planner.getAgentContext().whoami());
1067 
1068          g.setFact(needed);
1069          double t = planner.getAgentContext().now() +
1070                     planner.getAgentContext().getReplanPeriod();
1071          g.setConfirmTime(new Time(t));
1072          g.setSuppliedDb(null);
1073       }
1074       else {
1075          g = goal;
1076       }
1077 
1078       Core.DEBUG(3,"Top goal... soft internal replanning");
1079 
1080       this.removeRecordTree(struct.internal);
1081       planner.schedule(key,null,path,g,other_tasks,struct,Planner.EXPAND);
1082 
1083       if ( struct.internal.isEmpty() && mode == Planner.REPLAN ) {
1084          Vector goals = new Vector();
1085          goals.addElement(goal);
1086          DelegationStruct ds = new DelegationStruct(
1087             planner.getAgentContext().whoami(),"failure",
1088             exception_key,goals);
1089          planner.getAgentContext().Engine().add(ds);
1090       }
1091    }
1092    
1093 
1094    public void removeRecordTree(Vector data) {
1095       data.removeElement(this);
1096       PlanRecord[] children = getChildren();
1097       for(int i = 0; i < children.length; i++ )
1098          children[i].removeRecordTree(data);
1099    }
1100    
1101 
1102    public ReportRec report() {
1103       String parent_id = parent != null ? parent.getGoal().getId() : null;
1104 
1105       Vector siblings = new Vector();
1106       if ( goal.getImage() != null )
1107          siblings.addElement(goal.getImage());
1108 
1109       Vector parents = producedDb.getAllParents();
1110       parents.removeElement(goal.getId());
1111 
1112       ReportRec report = new ReportRec(goal.getId(), goal.getFactType(),
1113          task.getName(), planner.getAgentContext().whoami(),
1114          state, goal.getDesiredBy(),
1115          goal.getRootId(), parent_id,
1116          start_time, end_time, cost,
1117          consumedDb.allSubgoals(), siblings, parents,
1118          task.getPreconditions(), task.getPostconditions()
1119       );
1120       return report;
1121    }
1122    
1123 
1124    public Goal createSubgoal(Fact fact, int precon_position) {
1125       String goalId = planner.getAgentContext().newId("subgoal");
1126       String myself = planner.getAgentContext().whoami();
1127 
1128       Goal g = new Goal(goal.whichType(),goalId,fact,myself);
1129 
1130       if ( goal.whichType() == Goal.CONTINUOUS ) {
1131          g.setStartTime(start_time);
1132          g.setEndTime(end_time - task.getTime());
1133          g.setInvocations(goal.getInvocations());
1134       }
1135       else {
1136          g.setEndTime(start_time);
1137       }
1138       g.setConfirmTime(goal.getConfirmTime());
1139       g.setPriority(goal.getPriority());
1140       g.setCost(0);
1141       g.setRootId(goal.getRootId());
1142 
1143       g.setSuppliedDb(this.goal.getSuppliedDb());
1144 
1145       consumedDb.add(precon_position, g.getId(), fact.getNumber());
1146 
1147       return g;
1148    }
1149       
1150       
1151    public boolean hasSubgoal(String goalId) {
1152       return consumedDb.currentSubgoals().contains(goalId);
1153    }
1154    
1155    
1156    public boolean hasSubgoal(Goal goal) {
1157       return consumedDb.currentSubgoals().contains(goal.getId());
1158    }
1159 
1160 
1161    public boolean equals(PlanRecord rec)  {
1162       return id.equals(rec.getId()) &&
1163              goal.equals(rec.getGoal()) &&
1164              task.equals(rec.getTask());
1165    }
1166 
1167 
1168    public PlanRecord enact(PlannerEnactStruct es, Goal goal_image,
1169                            PlanRecord parent_image, String key_image,
1170                            Hashtable substitution_table) {
1171       System.out.println("ENACTING...."); 
1172       Fact fact = goal_image.getFact();
1173       int required = fact.getNumber();
1174       int etime = goal_image.getEndTime();
1175       int duration = task.getTime();
1176 
1177       etime = (etime <= 0) ? end_time + etime : etime;
1178       goal_image.setEndTime(etime);
1179 
1180       Core.DEBUG(4,"required = " + required);
1181       Core.DEBUG(4,"noAllowedInvocations = " + noAllowedInvocations);
1182       Core.DEBUG(4,"noAvailableItems = " + noAvailableItems);
1183       Core.DEBUG(4,"etime = " + etime);
1184       Core.DEBUG(4,"end_time = " + end_time);
1185       Core.DEBUG(4,"start_time = " + start_time);
1186       Core.DEBUG(4,"duration = " + duration);
1187 
1188       es.ok = es.ok &&
1189               goal.whichType() == Goal.CONTINUOUS && // prior SLA
1190               goal_image.whichType() == Goal.DISCRETE  && // enactment of SLA
1191               etime <= end_time && // time check
1192               etime >= start_time + duration &&
1193               noAllowedInvocations > 0 && // within allowed no. of enactments
1194               required <= noAvailableItems; // within allowed no of items
1195 
1196       if ( !es.ok ) {
1197          Core.DEBUG(4,"Failed here");
1198          return null;
1199       }
1200 
1201       boolean found = false;
1202       int top = 0, bottom = 0;
1203       for(int i = etime-start_time-1; !found && i >= duration-1; i-- ) {
1204          found = true;
1205          top = i; bottom = top-duration+1;
1206          for(int j = top; j >= bottom; j-- )
1207             found = found && slots[j] != BOOKED;
1208       }
1209       if ( !found ) {
1210          es.ok = false;
1211          return null;
1212       }
1213        System.out.println("ENACTING"); 
1214       PrimitiveTask task_image = new PrimitiveTask(task);
1215       
1216       // maintain everything except no. of items being produced
1217       // and consumed -- this should be taken care of by unifying
1218       // with the goal_image and applyConstraints
1219 
1220       task_image.relaxNumberFields();
1221 
1222       Core.DEBUG(4,"TaskImage Before = \n" + task_image.pprint());
1223      
1224       Bindings b = new Bindings(planner.getAgentContext().whoami());
1225       Fact f2 = task_image.getActiveEffect();
1226       es.ok = es.ok && f2.unifiesWith(fact,b) &&
1227               b.add(es.bindings) &&
1228               task_image.applyConstraints(b);
1229 
1230       Core.DEBUG(4,"TaskImage After = \n" + task_image.pprint());
1231 
1232       if ( !es.ok )
1233          return null;
1234 
1235 
1236       PlanRecord image = new PlanRecord(planner, this, key_image, parent_image,
1237          goal_image, task_image, proc, start_time+bottom, start_time+top+1);
1238 
1239       images.addElement(image);
1240       image.setAlternativeTasks(Misc.copyVector(other_tasks)); // poor copy
1241       image.setPath(Misc.copyVector(path)); // poor copy
1242       for(int i = start_time+top; i > start_time+top-duration; i-- ) {
1243          Core.DEBUG(4,"Assigning cell[" + proc + "][" + i + "] to "+image);
1244          planner.assignCell(proc,i,image);
1245       }
1246 
1247       substitution_table.put(this,image);
1248       es.images.addElement(image);
1249       producedDb.share(image.getProducedDb(),
1250                        parent_image, key_image, parent, key);
1251       consumedDb.share(image.getConsumedDb());
1252 
1253       // Note: negative s_etime. Subgoal will use this as offset to compute
1254       // their required etime;
1255       int s_etime = etime - end_time; 
1256 
1257       Goal child_goal_image;
1258       PlanRecord child;
1259       PlanRecord child_image;
1260       Object any;
1261       String goal_id;
1262       Fact f1;
1263 
1264       Hashtable children = image.getConsumedDb().getAllChildren();
1265       Enumeration enum = children.keys();
1266       while( enum.hasMoreElements() ) {
1267 
1268          f1 = (Fact) enum.nextElement();
1269          any = children.get(f1);
1270 
1271          String goalId = planner.getAgentContext().newId("subgoal");
1272          String myself = planner.getAgentContext().whoami();
1273 
1274          child_goal_image = new Goal(Goal.DISCRETE,goalId,f1,myself);
1275          child_goal_image.setEndTime(s_etime);
1276          child_goal_image.setPriority(goal.getPriority());
1277          child_goal_image.setCost(0);
1278          child_goal_image.setRootId(goal_image.getRootId());
1279 
1280          if ( any instanceof String ) {
1281             goal_id = (String)any;
1282             image.getConsumedDb().update(child_goal_image.getId(),goal_id);
1283             es.external.addElement(child_goal_image);
1284             es.table.put(child_goal_image.getId(),goal_id);
1285          }
1286          else {
1287             child = (PlanRecord)any;
1288             child_image = (PlanRecord)substitution_table.get(child);
1289             if ( child_image == null )
1290                child_image = child.enact(es,child_goal_image,image,key_image,
1291                                          substitution_table);
1292             Assert.notNull(child_image);
1293             image.getConsumedDb().update(child_image,child);
1294          }
1295       }
1296 
1297       for(int j = top; j >= bottom; j-- )
1298          slots[j] = BOOKED;
1299 
1300       noAllowedInvocations--;
1301       noAvailableItems = noAvailableItems - required;
1302       return image;
1303    }
1304 
1305    public String toString() {
1306       return id + "/" + goal.getFactType() + "/" + goal.getFactId() + "/" + key;
1307    }
1308 
1309     public void debug (String str) { 
1310       //  System.out.println("PlanRecord>> " +str); 
1311     }
1312 
1313 }