package org.jcon.ba.system;

import org.jcon.param.Param;
import org.jcon.util.minor.BetterHashtable;
import org.jcon.util.DataLib;
import org.jcon.util.GenLib;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;

/**
 * Defines the initial state of a Basket. Designed to be
 * the bridge mechanism between a Basket and Param
 * persistence. Hence the contents are reducible to text.
 *
 * @author Jack Harich
 */
public class BasketDef {

//---------- Private Fields ------------------------------
//----- Properties
private boolean  isPrimordialInvocated;
private Param    param;
private String[] autoConfigItemNames;

//----- Internal
// Key = itemName, Object = ItemDef
private BetterHashtable itemDefs = new BetterHashtable();

private Vector primordialInvocations = new Vector();

private static final String AUTO_CONFIG = "AutoConfig";
//---------- Properties ----------------------------------
//----- param
public void setParam(Param param) {
    this.param = param;
    itemDefs.clear();
    primordialInvocations.removeAllElements();

    String line;
    String[] keys = param.getDataKeys();

    for (int i = 0; i< keys.length; i++) {
        String key = keys[i].intern();
        if (key == "PrimordialInvocations") {
            // PrimordialInvocations
            Vector inv = param.getLinesVector("PrimordialInvocations");
            for (int j = 0; j < inv.size(); j++) {
                line = (String)inv.elementAt(j);
                //print(".setParam() - primordialInvocation line " + line);
                primordialInvocations.addElement(line);
            }
        } else if (key.endsWith("_Item")) {
            // Must be an item definition
            Param itemParam = param.getParam(key);
            ItemDef itemDef = createItemDef(key, itemParam);
            addItemDef(itemDef);
            //print(".toModuleDef() - added ItemDef key = " + key);
        } else if (key == AUTO_CONFIG) {
            // Do nothing
        } else {
            GenLib.error("BasketDef.setParam()",
                "Unknown key '" + key + "' in basket param.");
        }
    }
    initAutoConfigItemNames(param);
}
public Param getParam() {
    return param;
}
//----- isInvocated
/**
* Sets the PrimordialInvocated property, which if true
* means that primordial invocations have already been 
* called for this Basket. 
*/
public void setPrimordialInvocated(boolean isPrimordialInvocated) {
    this.isPrimordialInvocated = isPrimordialInvocated;
}
public boolean isPrimordialInvocated() {
    return isPrimordialInvocated;
}
//----- Other
public String[] getAutoConfigItemNames() {
    return autoConfigItemNames;
}
//---------- Public Methods ------------------------------
//----- ItemDefs
/**
 * Adds the ItemDef to this class's internal collection.
 * Complains and does not add it if itemDef.getItemName()
 * is already in the collection, since duplicate itemNames
 * are not allowed in a module.
 */
public void addItemDef(ItemDef itemDef) {
    String itemName = itemDef.getItemName();
    if (itemDefs.get(itemName) != null) {
        GenLib.error("BasketDef.addItemDef()",
            "ItemName '" + itemName + "' is already in this ModuleDef.");
    } else {
        itemDefs.put(itemName, itemDef);
    }
}
/**
 * Returns an array of all the itemNames in this
 * ModuleDef. These can then be used to get each ItemDef.
 * These are in the order added, which is the logical order.
 * "this" is excluded.
 */
public String[] getItemNames() {
    String[] names = new String[itemDefs.size() - 1];
    int index = 0;
    Enumeration enum = itemDefs.getOrderedKeys();
    while (enum.hasMoreElements()) {
        String itemName = (String)enum.nextElement();
        if (itemName.equals("this")) continue;
        names[index++] = itemName;
    }
    return names;
}
/**
 * Returns a list of all item names, delimited by a line
 * return. This is for debugging.
 */
public String listItemNames() {
    String list = "";
    String[] itemNames = getItemNames();
    for (int i = 0; i < itemNames.length; i++) {
        list += itemNames[i] + "\n";
    }
    return list;
}
/**
 * Returns the named ItemDef. Complains and returns null if
 * not found.
 */
public ItemDef getItemDef(String itemName) {
    ItemDef itemDef = (ItemDef)itemDefs.get(itemName);
    if (itemDef == null) {
        GenLib.error("BasketDef.getItemDef()",
            "ItemName '" + itemName + "' not found in this BasketDef."
                + "\nMy item names are:\n" + listItemNames());
        // List items names
        print(".getItemDef() - " + getItemCount()  + " item names are:\n" + listItemNames());
    }
    return itemDef;
}
/**
 * Returns the total number of ItemDefs, which may be zero.
 * "this" is excluded, so the result is total - 1.
 */
public int getItemCount() {
    return itemDefs.size() - 1;
}
//----- primordialInvocations
public Vector getPrimordialInvocations() {
    return primordialInvocations;
}
//----- Other
/**
* Sets all invocated to false.
*/
public void close() {
    isPrimordialInvocated = false;
    String[] names = getItemNames();
    for (int i = 0; i < names.length; i++) {
        getItemDef(names[i]).setInvocated(false);
    }   
}
//---------- Private Methods -----------------------------
private ItemDef createItemDef(String key, Param itemParam) {
    ItemDef def = new ItemDef();

    String itemName = key.substring(0, key.lastIndexOf("_Item") );
    def.setItemName(itemName);

    // Set properties

    // false if none
    def.setContainer(itemParam.isTrueDefaultFalse("IsContainer"));

    // null if none
    if (itemParam.hasProperty("Config")) {
        def.setConfigLines(itemParam.getLinesVector("Config"));
    }
    def.setBeanClassName(itemParam.getString("BeanClassName"));
    def.setMarkerClassName(itemParam.getString("MarkerClassName"));

    if (itemParam.hasProperty("ParamMarkerItemName")) {
        // Only needed for ParamDriven items and not "this"
        def.setParamMarkerItemName(itemParam.getString("ParamMarkerItemName"));
        def.setParamFileName(itemParam.getString("ParamFileName"));
        
    } else if (itemParam.hasProperty("ParamMarkerClassName")) {
        // For parex reuse from outside of tree
        def.setParamMarkerClassName(itemParam.getString("ParamMarkerClassName"));
        def.setParamFileName(itemParam.getString("ParamFileName"));
    }
    return def;
}
private void initAutoConfigItemNames(Param param) {
    String names = param.getString(AUTO_CONFIG);
    if (names == null) {
        autoConfigItemNames = new String[0];    
    } else {
        autoConfigItemNames = DataLib
            .convertDelimStringToArray(names, ", ");
    }
}
//--- Std
private static void print(String text) {
    System.out.println("BasketDef" + text);
}


} // End class
