/*
** Module   : DependentElement.java
** Abstract : represents an element that is dependent upon another element
**
** Copyright (c) 2009, Golden Code Development Corporation.
**
** -#- -I- --Date-- -----------------------Description------------------------
** 001 GES 20090319 Represents an element that is dependent upon another
**                  element.
*/

/*
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU Affero General Public License as
** published by the Free Software Foundation, either version 3 of the
** License, or (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU Affero General Public License for more details.
**
** You should have received a copy of the GNU Affero General Public License
** along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

package com.goldencode.harness;

import com.goldencode.harness.test.*;

/**
 * Represents an element that is dependent upon another element. This element
 * will not be returned until the element upon which it depends is successfully
 * processed. If the element upon which this depends (or one on which that
 * element depends and so on) is processed with a failed status, this element
 * will be marked as failed and will no longer be returned.
 * 
 * @param   <E>
 *          Type of element.
 */
public class DependentElement<E extends Test>
extends SingleElement<E>
implements Dependent
{
   /** Flag to track ready status. */
   private boolean ready = false;
   
   /**
    * Construct an instance.
    *
    * @param    element
    *           The element to return from the queue.
    * @param    dependee
    *           The element on which processing depends.
    */
   public DependentElement(E element, E dependee)
   {
      super(element);
      dependee.addDependent(this);
   }
   
   /**
    * Reports if the queue has elements to {@link #dequeue}. This will be
    * <code>false</code> if there are no elements remaining OR if the elements
    * that are contained have dependencies upon other elements such that no
    * dequeuing is possible until the dependencies are satisfied. In such a
    * case the queue is considered not ready.
    *
    * @return   <code>true</code> if the queue contains at least one element
    *           which is ready to be dequeued AND the calling thread is the
    *           thread on which the tests must run.
    */
   public synchronized boolean isReady()
   {
      return ready && super.isReady();
   }
   
   /**
    * Associates the next element in the queue with the caller, without
    * actually calling {@link #dequeue} which can block. This allows the
    * calling code to release any resources before the subsequent potentially
    * blocking operation. Any subsequent call to {@link #isReady} MUST take
    * this reservation into account. This means that all calls to this method
    * must be matched with a subsequent call to <code>dequeue</code>.
    *
    * @return   <code>true</code> if the reservation was successful. Otherwise
    *           the queue is not ready and caller MUST NOT call
    *           <code>dequeue</code>. 
    */
   public synchronized boolean reserve()
   {
      return ready && super.reserve();
   }
   
   /**
    * Reports on the disposition of an activity on which this object is
    * dependent.
    *
    * @param    status
    *           The status of the activity.
    * @param    reason
    *           Details on the cause of any failure.
    */
   public synchronized void update(Status status, String reason)
   {
      if (status != Status.PASSED)
      {
         Test element = getElement();
         
         // this will trigger a cascade of updates to all other elements
         // that are dependent upon our element
         element.setStatus(Status.FAILED_DEPENDENCY, reason);
         setElement(null);
      }
      else
      {
         ready = true;
      }
   }
}
