package org.jcon.ba.system;

import org.jcon.param.ParamStore;
import org.jcon.util.GenLib;
import org.jcon.util.PropMap;
import org.jcon.util.PropMapStd;
import java.util.StringTokenizer;
import java.util.Vector;
import org.jcon.util.service.ContainerServices;

/**
 * Provides services for using a Basket's items.
 * This allows the items to collaborate efficiently while
 * preserving loose coupling.
 *
 * Note that Item, BeanWrapper, Basket, etc are not exposed to
 * preserve the all important loose coupling between the
 * Bean Assembler and the systems built with it.
 *
 * @author Jack Harich
 */
public class BasketServices {

//---------- Private Fields ------------------------------
private Basket  basket;
private PropMap propMap = new PropMapStd();

//---------- Initialization ------------------------------
public BasketServices(Basket basket) {
    this.basket = basket;
}
//---------- Properties ----------------------------------
public ContainerServices getContainerServices() {
    return basket.getContainerServices();
}
/**
 * Used to set named system properties for this container.
 * Provided to pass CommandArgs to the root container and
 * possible other use.
 * See getSystemProperty() and hasSystemProperty() for how
 * to read these properties once they are set. ******
 *
 * get and has are disabled. We are waiting to see if they
 * are necessary and proper. They introduce a non-event
 * dependency, and so break the Structured Assembly axioms.
 */
public PropMap getPropMap() {
    return propMap;
}
/**
 * Non-BA business objects should not use this method,
 * since it exposes Item. FOR INTERNAL USE ONLY.
 */
// Used by ba.Mediator to open a tree.
public Item getRootItem() {
    return basket.getOwnerItem().getRootItem();
}
public int getItemCount() {
    return basket.getItemCount();
}
/**
* Returns the parent of this instance or null if the 
* parent is the root.
*/
public BasketServices getParent() {
	if (basket.getOwnerItem().isRoot()) {
		return null;
	} else {
		return basket.getOwnerItem().getParentItem()
			.getBasket().getBasketServices();
	}
}
/**
 * Returns a String array of the item names in this basket.
 * Does not cause the items to be instantiated.
 */
public String[] getItemNames() {
    return basket.getItemNames();
}
public ParamStore getParamStore() {
    return basket.getOwnerItem().getItemSystem().getParamStore();
}
//---------- Public Methods ------------------------------
//----- Item mutators (not all used yet)
public void startItem(String itemName) {
    Item item = basket.getLiveItem(itemName);
    if (item.isStartable()) {
        item.start();
    } else {
        complainWhyCantMutateItem(item, "not startable");
    }
}
public void pauseItem(String itemName) {
    Item item = basket.getLiveItem(itemName);
    if (item.isPausable()) {
        item.pause();
    } else {
        complainWhyCantMutateItem(item, "not pausable");
    }
}
public void resumeItem(String itemName) {
    Item item = basket.getLiveItem(itemName);
    if (item.isResumable()) {
        item.resume();
    } else {
        complainWhyCantMutateItem(item, "not resumable");
    }
}
public String canCloseItem(String itemName) {
    Item item = basket.getLiveItem(itemName);
    if (item.isClosable()) {
        return item.canClose();
    } else {
        return null; // Yes
    }
}
public void closeItem(String itemName) {
    Item item = basket.getLiveItem(itemName);
    if (item.isClosable()) {
        item.close();
    } else {
        complainWhyCantMutateItem(item, "not closable");
    }
}
//----- Other
/**
 * Returns an indented String representation of the tree
 * starting at the root. Designed for testing.
 */
public String listItemTree() {
    return basket.getOwnerItem().getNode().getRootNode().listTree();
}
/**
 * Returns a String array of the item names in
 * basketItemName, which must be a container. Returns null
 * and complains if not a container. "this" can be used to
 * refer to this basket.
 *
 * Causes the basketItemName to be opened, but doesn't cause
 * its items to be instantiated.
 */
public String[] getBasketItemNames(String basketItemName) {
    Item item = basket.getLiveItem(basketItemName);
    if (! item.isContainer()) {
        GenLib.error("BasketServices.getBasketItemNames()",
            "'" + basketItemName + "' is not a container.");
        return null;
    }
    return item.getBasket().getItemNames();
}
/**
 * Returns the BasketServices for basketPath, which
 * must be a container. Complains and retuns null if not
 * a container. This can cause basketPath to be
 * opened.
 *
 * The basketPath may be period delimited, which returns
 * the services for the last item name. If basketPath
 * is "" then this is returned.
 *
 * For example "schemaMgr.main" returns the services for the item named
 * "main" basket in the "schemaMgr" basket.
 */
public BasketServices getBasketServices(String basketPath) {
    BasketServices services = this;
    StringTokenizer names = new StringTokenizer(basketPath, ".");
    while (names.hasMoreTokens()) {
        String name = names.nextToken();
        services = services.basket.getLiveItem(name)
            .getBasket().getBasketServices();
    }
    return services;
}
/**
 * Loads and returns a Vector of all the BeanWrapper instances
 * in the branch named moduleName. This also has the effect
 * of opening the branch. Complains and returns null if not
 * a container. The Vector contains type Object.
 */
public Vector getBranchBeanInstances(String basketItemName) {
    Item item = basket.getLiveItem(basketItemName);
    if (! item.isContainer()) {
        GenLib.error("BasketServices.getBranchBeanInstances()",
            "'" + basketItemName + "' is not a container.");
        return null;
    }
    Basket branchBasket = item.getBasket();
    branchBasket.openBranch(); // Crucial
    Vector instances = new Vector();
    branchBasket.loadBranchBeanInstances(instances);
    return instances;
}
/**
* Returns the BeanWrapper instance named itemName. 
* Complains and returns null if not found or the item is
* a container.
*/
public Object getBeanInstance(String itemName) {
    Item item = basket.getLiveItem(itemName);
    if (item.isContainer()) {
        GenLib.error("BasketServices.getBeanInstance()",
            "'" + itemName + "' is a container.");
        return null;
    } else {
		return item.getBeanInstance();
	}
}
/**
 * Returns all the BeanWrapper instances in this basket.
 */
public Vector getBeanInstances() {
    Vector beans = new Vector();
    String[] names = getBasketItemNames("this");
    for (int i = 0; i < names.length; i++) {
        //print(".getBeanInstances() - Checking name " + names[i]);    
        Item item = basket.getLiveItem(names[i]);
        if (item.isBeanWrapper()) {
            beans.addElement(item.getBeanInstance());       
        }
    }
    return beans;
}
/**
 * Returns all the BeanWrapper instances in this branch.
 */
public Vector getBranchBeanInstances() {
    basket.openBranch(); // Crucial
    Vector instances = new Vector();
    basket.loadBranchBeanInstances(instances);
    return instances;
}
/**
 * Returns the named property by starting at this container
 * and searching upward until found. Complains and returns
 * null if not found. Note that null can be a legimitate
 * return value. RECURSIVE.  (UNTESTED ***)
 */
/** public Object getSystemProperty(String propertyName) {
    if (propMap.has(propertyName)) {
        return propMap.get(propertyName);
    } else if (basket.getOwnerItem().isRoot()) {
        GenLib.error("BasketServices.getSystemProperty()",
            "Property '" + propertyName + "' not found.");
        return null;
    } else {
        return basket.getOwnerItem().getParentItem().getBasket()
        .getBasketServices().getSystemProperty(propertyName);
    }
} */
/**
 * Returns true if the named property exists, false if not.
 * Useful to determine if a property is defined or to
 * determine if a property value is null or merely not
 * found. RECURSIVE.  (UNTESTED ***)
 */
/** public boolean hasSystemProperty(String propertyName) {
    if (propMap.has(propertyName)) {
        return true;
    } else if (basket.getOwnerItem().isRoot()) {
        return false;
    } else {
        return basket.getOwnerItem().getParentItem().getBasket()
        .getBasketServices().hasSystemProperty(propertyName);
    }
} */
//---------- Private Methods -----------------------------
private void complainWhyCantMutateItem(Item item,
        String notPhrase) {
    GenLib.helpfulHint("Item '" + item.getItemName() +
"' is " + notPhrase + "." +
"\nThat item's state is '" + item.getItemStateString() + "'.");
}
//--- Std
private static void print(String text) {
    System.out.println("BasketServices" + text);
}

} // End class
