package org.jcon.df.edit;

import org.jcon.df.edit.control.Control;
import org.jcon.df.edit.control.ControlFactory;
import org.jcon.df.edit.module.Module;
import org.jcon.df.edit.module.ModuleFactory;
import org.jcon.df.edit.widget.Widget;
import org.jcon.param.Param;
import org.jcon.ui.VisualLib;
import org.jcon.ui.easylayout.EasyLayout;
import org.jcon.util.DataLib;
import org.jcon.util.GenLib;
import java.awt.*;
import java.util.Hashtable;
import java.util.Vector;
import javax.swing.JComponent;

/**
 * Configures components using a layout and param.
 * This is done by using the Param to create, configure
 * and layout components.
 *
 * @author Jack Harich
 */
public class ComponentConfig {

//---------- Private Fields ------------------------------
// Properties or creational args
private EasyLayout       layout;
private Param            myParam;
private EditListener     editListener;
private String           dataSourceID;

// Internal
private Vector           controls = new Vector();
private Vector           modules = new Vector();

//---------- Initialization ------------------------------
public ComponentConfig(EasyLayout layout,
        Param param, EditListener editListener) {
    this.layout = layout;
    myParam = param;
    this.editListener = editListener;
}
//---------- Properties ----------------------------------
// Used for provideColumnDef(), not to pass to worker,
// which would be a Bad Thing
public void setDataSourceID(String dataSourceID) {
    this.dataSourceID = dataSourceID;
}
public Vector getControls() {
    return controls;
}
public Vector getModules() {
    return modules;
}
/**
* Returns the Module having all the other Widgets or
* returns a Control if this only has a Control. This is
* useful for situations such as setting the focus on a
* Widget.
*/
public Widget getTopWidget() {
    if (! modules.isEmpty()) {
        return (Widget)modules.firstElement();
    } else {
        return (Widget)controls.firstElement();
    }
}
//---------- Public Methods ------------------------------
/**
* Configures the components. After this getters can be
* used.
*/
public void config(){
    controls.removeAllElements();
    modules.removeAllElements();
    if (myParam == null) {
        throw new IllegalStateException("myParam is null. " +
        "You are probably missing a 'NestedContainer'.");
    } else {
        addWorkers(myParam);
    }
}
//---------- Private Methods -----------------------------
// RECURSIVE - Stops if Module or not nested
private void addWorkers(Param param) {
    String[] names = param.getDataKeys();
    for (int i = 0; i < names.length; i++) {
        //print(".addWorkers() - adding '" + names[i] + "'");
        addWorker(names[i], param.getParam(names[i]));
    }
}
// Each worker is a Component or Module
private void addWorker(String name, Param param) {
    // Set isModule
    boolean isModule = param.isTrueDefaultFalse("IsModule");

    // Add Module or Control
    if (isModule) {
        Module module = ModuleFactory.createModule(
            name, param);
        modules.addElement(module);
        module.setEditListener(editListener);
        module.setParam(param); // Must be after setEditListener()
        Component comp = module.getComponent();
        addComponent(comp, name, param);
        // Module will handle its own
        return; // END RECURSION
    } else {
        Control control = ControlFactory.createControl(
            name, param);
        controls.addElement(control);
        control.setEditListener(editListener);
        provideColumnDef(control);
        provideEditAllowed(control, param);
        control.init();
        addComponent(control.getComponent(), name, param);
    }
    // Recurse if nested
    if (param.hasProperty("NestedContainer")) {
        layout.beginNestedContainer();
            addWorkers(param.getParam("NestedContainer"));
        layout.endNestedContainer();
    }
}
private void addComponent(Component comp, String name,
      Param param) {
    String styleName = param.getString("Style");
	if (styleName == null) {
			styleName = "Default";
	}
    //print(".addComponent() - adding " + name + ", " + styleName);
    String addType = param.getString("AddType"); // null if none

    if (param.hasProperty("StyleProperties")) {
        layout.useStyle(styleName);
        configStyle(comp, name, param.getParam("StyleProperties"));
        layout.add(comp, null, addType);
    } else {
        layout.add(comp, styleName, addType);
    }
}
private void configStyle(Component comp, String name, Param param) {

String[] properties = param.getDataKeys();

for (int i = 0; i < properties.length; i++) {
String property = properties[i].intern();

//---------------------------------
if(property == "Alignment") {
    layout.setAlignment(param.getString("Alignment"));

} else if(property == "Stretch") {
    layout.setStretch(param.getString("Stretch"));

//---------------------------------
} else if(property == "WidthWeight") {
//print(" - Setting WidthWeight to " + param.getInt("WidthWeight"));
    layout.setWidthWeight(param.getDouble("WidthWeight"));

} else if(property == "HeightWeight") {
//print(" - Setting HeightWeight to " + param.getInt("HeightWeight"));
    layout.setHeightWeight(param.getDouble("HeightWeight"));

} else if(property == "Row") {
    layout.setRow(param.getInt("Row"));

} else if(property == "Column") {
    layout.setColumn(param.getInt("Column"));

} else if(property == "RowColumn") {
    int[] args = DataLib.createIntArray(param.getString("RowColumn"));
    layout.setRowColumn(args[0], args[1]);

//---------------------------------
} else if (property == "Insets") {
    int[] args = DataLib.createIntArray(param.getString("Insets"));
    layout.setInsets(args[0], args[1], args[2], args[3]);

} else if(property == "InsetTop") {
    layout.setInsetTop(param.getInt("InsetTop"));

} else if(property == "InsetLeft") {
    layout.setInsetLeft(param.getInt("InsetLeft"));

} else if(property == "InsetBottom") {
    layout.setInsetBottom(param.getInt("InsetBottom"));

} else if(property == "InsetRight") {
    layout.setInsetRight(param.getInt("InsetRight"));

//---------------------------------
} else if(property == "GridWidth") {
    layout.setGridWidth(param.getInt("GridWidth"));

} else if(property == "GridHeight") {
    layout.setGridHeight(param.getInt("GridHeight"));

} else if(property == "GridWidthHeight") {
    int[] args = DataLib.createIntArray(param.getString("GridWidthHeight"));
    layout.setGridWidthHeight(args[0], args[1]);

} else if(property == "ExtraSizeWidth") {
    layout.setExtraSizeWidth(param.getInt("ExtraSizeWidth"));

} else if(property == "ExtraSizeHeight") {
    layout.setExtraSizeHeight(param.getInt("ExtraSizeHeight"));
//---------------------------------
} else if (property == "PreferredSize") {
    if (comp instanceof JComponent) {
        String size = param.getString("PreferredSize");
        ((JComponent)comp).setPreferredSize(
            VisualLib.parseDimension(size));

    } else {
        print(".configStyle() - Cannot config '" + name + "' to PreferredSize since not JComponent");
    }
//---------------------------------
} else {
    GenLib.error("ComponentConfig.configStyle()",
        "Unknown style property '" + property + "'.");
} // End if
} // End for
} // End method

private void provideColumnDef(Control control) {
    if (dataSourceID != null &&
            control.getColumnID() != null) {
        //print(" control.getColumnID() = " + control.getColumnID());
        EditEvent evt = new EditEvent(EditEvent
            .ACQUIRE_COLUMN_DEF, dataSourceID);
        evt.setColumnID(control.getColumnID() );
        editListener.processEditEvent(evt);
        if (evt.getColumnDef() == null) {
            GenLib.error("ComponentConfig.provideColumnDef()",
                "Failed to acquire ColumnDef for " + control.getColumnID());
        } else {
            control.setColumnDef(evt.getColumnDef());
        }
    }
}
private void provideEditAllowed(Control control, Param param) {
    // Default is true, a rarity for boolean
    control.setEditAllowed(param.isTrueDefaultTrue("EditAllowed"));
}
//--- Std
private static void print(String text) {
    System.out.println("ComponentConfig" + text);
}

} // End class
