/**
 * File: Supplier.java
 * Description:
 *  Took out "dominates" and added precedence 
 *  for both Supplier and ConcreteSupplier
 *
 **/

package lawOfDemeter;
import java.util.*;

/**
 * The Supplier class is a  super class for the bin aspects.
 * It provides common functionality around a HashMap (targets)
 * that keeps track of the preferred supplier objects stored in the
 * various bins.
 *
 * @author David H. Lorenz
 * @author Modifications made by Paul Freeman
 */
abstract aspect Supplier {
        declare precedence : Supplier, Checker;
        protected final static String argument = " OK--Argument";
	protected final static String local    = " OK--New, local, or static";
	protected final static String direct   = " OK--Instance variable";
	protected final static String receiver = " OK--Receiver";

	protected IdentityHashMap targets=new IdentityHashMap();
        private static Vector suppliers = new Vector(); // used to hold all the
                                                        // suppliers available to
                                                        // the checker aspect

        /**
         * Adds the target as the key and the String i as the value to the
         * container of targets in this supplier.
         *
         * @param target
         * @param i
         */
	void add(Object target,String i) {
            if(target != null){
              targets.put(target,i);
            }
	}

        /**
         * Adds all of the targets in the target list to the container of targets
         * with the target as the key and the String i as the value.
         *
         * @param targetlist
         * @param i
         */
	void addAll(Object[] targetlist,String i) {
		for (int k=0; k<targetlist.length; k++)
			add(targetlist[k],i);
	}

        /**
         * @param target
         * @return Returns true if the supplier contains the target and false
         * otherwise.
         */
	boolean contains(Object target) {
		if (targets.containsKey(target)) {
			return true;
		}
		return false;
	}

        // returns a string identifying the location of the join point
	protected String at(org.aspectj.lang.JoinPoint jp) {
		return JPUtil.at(jp);
	}

        /**
         * Prints the list of targets in the HashMap argument.
         */
	protected void printHashMap(IdentityHashMap targets) {
                Object[] values = targets.entrySet().toArray();
		for (int v=0; v<values.length; v++){
                  System.out.println("" + values[v]);
		}
        }
        /**
         * Prints the objects currently in the bin.
         * Used for debugging.
         */
        public void printTargets(){
          System.out.println("== "+this.contains()+" for "+thisObject+" ==");

          printHashMap(targets);
          System.out.println("======================");
        }

        /**
         * Used in debugging print statements.
         * @return Returns a string describing what this supplier contains.
         */
        abstract String contains();



    /* The following functions improve the unit testing and separation of concerns
     * in the LoD Checker by removing from the Checker the knowledge of what
     * suppliers are available.
     * Logic:
     *  Since Supplier dominates Checker, each class
     *  that extends supplier will add itself to the static list of Suppliers
     *  stored here in the super class (using the before advice below),
     *  prior to the check of the same join point in the checker class.
     *  The checker aspect will now only need to call the static getSuppliers
     *  method to get the list of suppliers available for a particular check.
     */

        /**
         * Since some suppliers may not be singleton suppliers, this function
         * must be used to return the correct supplier for the supplied object.
         *
         * @param thisObj
         * @return Returns the correct supplier for the supplied Object thisObject
         * if there is one, else returns null.
         */
        abstract public Supplier getSupplier(Object thisObj);

        /**
         * Advice that gathers supplier objects at a join point before that
         * join point is checked in the checker aspect.
         */
        Object thisObject;
        before():
          Any.ToCheck(){
            thisObject = thisJoinPoint.getThis();
            Supplier s = getSupplier(thisJoinPoint.getThis());
            if(s != null){
              suppliers.add(s);
            }
        }

        /**
         * This function returns the Vector of current suppliers to be
         * examined during a check.
         * The list is:
         *  initialized prior to any check by the concrete supplier aspect
         *  populated prior to any check by all aspects that impliment supplier
         *
         * @return Returns a Vector of the current suppliers available.
         */
        protected static Vector getSuppliers(){
          return suppliers;
        }
}

/**
 * This aspect initializes the static Vector of Suppliers contained in Supplier
 * prior to any check.  This advice must be maintained in a concrete supplier
 * aspect, i.e. one that is not extended, since we want the advice to execute
 * only once, regardless of the number of suppliers being used in the Law of
 * Demeter Checker.
 *
 */
//privileged aspect ConcreteSupplier dominates Supplier {
privileged aspect ConcreteSupplier {
  declare precedence : ConcreteSupplier, Supplier;
  // initialize the suppliers vector
  before(): Any.ToCheck() {
    Supplier.suppliers = new Vector();
  }
}

