package org.jcon.df.edit;

import org.jcon.ba.system.BeanActionClose;
import org.jcon.ba.system.BeanActionStart;
import org.jcon.df.column.ColumnDef;
import org.jcon.df.edit.EditEvent;
import org.jcon.df.edit.EditListener;
import org.jcon.df.edit.module.Module;
import org.jcon.df.work.Row;
import org.jcon.df.work.RowSet;
import org.jcon.df.work.RowSource;
import org.jcon.param.Param;
import org.jcon.param.ParamDrivenInfo;
import org.jcon.param.ParamDrivenSupply;
import org.jcon.param.ParamSupplier;
import org.jcon.util.DataLib;
import org.jcon.util.GenLib;
import org.jcon.util.msg.Message;
import org.jcon.util.msg.MessageListener;
import org.jcon.util.service.ContainerServices;
import org.jcon.util.service.ContainerServicesUser;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;

/**
 * This class is a custom controller that uses a portion
 * of the data framework. It is a manual version of the
 * DataEditor for custom tasks. Its most important members
 * are the RowSources, which are interfaces.
 *   *** NOT USED, see org.jcon.test.app3 ***
 *   REPLACED BY Task classes
 *
 * @author Jack Harich
 */
public class CustomEditor implements BeanActionStart,
    BeanActionClose, MessageListener, EditListener,
    ParamDrivenSupply, ContainerServicesUser {

//---------- Private Fields ------------------------------
// Properties
private String    startMessageName;
private String    schemaName;
private ContainerServices containerServices;
// Internal
private boolean       started;
private ParamSupplier paramSupplier;
private Param         param;

// Key = viewName, Object = DataView
private Hashtable dataViews = new Hashtable();

// Key = DataSourceID, Object = RowSource
private Hashtable rowSources = new Hashtable();

//---------- BeanActionStart Implementation --------------
public void start() {
    if (started) {
        // Help the user by putting the focus back on the views
        showViews();
        return;
    }
    getParam();      // Late initialization
    // The 4 steps
    initSources();   // Must be before initViews()
    initViews();
    startSources();  // Will fire event to populate views
    showViews();     // To avoid showing while populating
        
    started = true; 
}
private void initSources() { // START STEP 1
    rowSources.clear();
    String text = param.getString("DataSourceIDs");
    String[] names = DataLib.convertDelimStringToArray(text, ", ");
    for (int i = 0; i < names.length; i++) {
        String sourceID = names[i];
        Param sourceParam = param.getParam(sourceID);
        String entityName = sourceParam.getString("EntityName");
        String className  = sourceParam.getString("RowSourceClass");        
        
        RowSource source = (RowSource)GenLib.createInstance(className);
        rowSources.put(sourceID, source);
        source.setID(sourceID);
        source.setEntityName(entityName);
        //source.setDatastoreServices(datastoreServices);
        //source.setDataSourceSupplier(this);
    } 
}  
private void initViews() { // START STEP 2
    dataViews.clear();
    String text = param.getString("ViewNames");
    String[] names = DataLib.convertDelimStringToArray(text, ", ");
    for (int i = 0; i < names.length; i++) {
        String name = names[i];
        DataView view = new DataView();
        dataViews.put(name, view);
        view.setViewName(name);
        view.setEditListener(this);
        view.setParam(param.getParam(name));
        view.init();
    }
}  
private void startSources() { // START STEP 3
    Enumeration enum = rowSources.elements();
    while (enum.hasMoreElements()) {
        RowSource rowSource = (RowSource)enum.nextElement();
        provideRowSetListeners(rowSource);
        rowSource.start();
    }
}
private void provideRowSetListeners(RowSource source) {
    String dataSourceID = source.getID();
    if (dataSourceID == null) return;
    
    Enumeration enum = dataViews.elements();
    while (enum.hasMoreElements()) {
        DataView view = (DataView)enum.nextElement();
        Vector modules = view.getAllModules();
        for (int i = 0; i < modules.size(); i++) {
            Module module = (Module)modules.elementAt(i);
            String moduleDataSourceID = module.getDataSourceID();
            //print(".provideRowSetListeners() - moduleDataSourceID = " + moduleDataSourceID + ", dataSourceID = " + dataSourceID);
            if (moduleDataSourceID == null) continue;

            if (moduleDataSourceID.equals(dataSourceID)) {
                source.addRowSetListener(module);
            }
        }
    }
}
private void showViews() { // START STEP 4
    Enumeration enum = dataViews.elements();
    while (enum.hasMoreElements()) {
        DataView view = (DataView)enum.nextElement();
        if (view.isPrimeView()) {
            view.setVisible(true);
        }
    }
}
//---------- BeanActionClose Implementation --------------
public String canClose() {
    return null; // Yes
}
public void close() {
    // Close views
    Enumeration enum = dataViews.elements();
    while (enum.hasMoreElements()) {
        DataView view = (DataView)enum.nextElement();
        view.close();
    }
    dataViews.clear();
    rowSources.clear(); // Close sources ???
    started = false;
    System.gc(); // To fix apparent bug when calling start() second time
}
//---------- MessageListener Implementation --------------
public void processMessage(Message message) {
    String messageName = message.getName();

    if (messageName == startMessageName) {
        start();

    } else {
        print(".processMessage() - Unknown messageName '" +
            messageName + "', startMessageName = " + startMessageName);
    }
}
public String[] loadMessageInterests() {
    if (startMessageName == null) {
        return new String[0];
    } else {
        return new String[] { startMessageName };
    }
}
//---------- EditListener Implementation -----------------
public void processEditEvent(EditEvent evt) {
    //print(".processEditEvent() - " + evt.getEventTypeString());
    
    if (evt.getEventType() == EditEvent.CLOSE) {
        closeViewRequested(evt.getViewName());
        return;
    }  
    // Set dataSourceID and source
    String dataSourceID = evt.getDataSourceID();
    if (dataSourceID == null) {
        GenLib.error("RowEditor.processEditEvent()",
            "dataSourceID is null in " + evt.getEventTypeString());
        return;
    }
    RowSource rowSource = getRowSource(dataSourceID);
    if (rowSource == null) {
        GenLib.error("RowEditor.processEditEvent()",
            "No source for dataSourceID '" + dataSourceID + "'.");
        return;
    }
    // Handle event
    switch(evt.getEventType()) {
        // *** This will be modified ***
        case EditEvent.ACQUIRE_COLUMN_DEF:
            String columnID = evt.getColumnID();
            evt.setColumnDef(getColumnDef(schemaName, columnID));
            break; 
        default:
            // Possibly add ContainerServices to event
            // So can use to getColumnDef() via Message
            rowSource.processEditEvent(evt);
            break;      
    }
}  
private ColumnDef getColumnDef(String schemaName,
                                        String columnID) {
    Message message = new Message("AcquireColumnDef");
    message.set("SchemaName", schemaName);
    message.set("ColumnID", columnID);
    containerServices.sendMessage(message);
    return (ColumnDef)message.get("ColumnDef");
}
//---------- ParamDrivenSupply Implementation ------------
public void setParamSupplier(ParamSupplier paramSupplier) {
    this.paramSupplier = paramSupplier;
}
public void setParam(Param param) {
    this.param = param;
}
public Param getParam() {
    if (param == null) {
        paramSupplier.supplyParam(this);
        paramSupplier = null;
    }
    return param;
}
public boolean applyNewParam(Param newParam) {
    param = newParam;
    boolean wasStarted = started;
    close();
    if (wasStarted) start();
    return true; // Successful
}
public ParamDrivenInfo getParamDrivenInfo() {
    return null;
}
//---------- ContainerServicesUser Implementation --------
public void setContainerServices(ContainerServices services) {
    containerServices = services;
}
public String[] getContainerServicesInterests() {
    return new String[0]; 
}
//---------- Properties ---------------------------------- 
//----- StartMessageName
public void setStartMessageName(String startMessageName) {
    this.startMessageName = startMessageName.intern();   
}    
public String getStartMessageName() {
     return startMessageName;   
} 
//----- SchemaName
public void setSchemaName(String schemaName) {
    this.schemaName = schemaName;   
}
public String getSchemaName() {
    return schemaName;   
}    
//---------- Public Methods ------------------------------

//---------- Private Methods -----------------------------
private void closeViewRequested(String viewName) {
    if (dataViews.size() == 1) {
        close();
    } else {
        DataView view = getDataView(viewName);
        if (view.isPrimeView()) {
            close();
        } else {
            view.setVisible(false);
        }
    }
}
// Returns null if not found
private DataView getDataView(String viewName) {
    return (DataView)dataViews.get(viewName);
}
// Returns null if not found
private RowSource getRowSource(String dataSourceID) {
    return (RowSource)rowSources.get(dataSourceID);
}    
//--- Std
private static void print(String text) {
    System.out.println("CustomEditor" + text);
}

} // End class
