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.edit.widget.WidgetSet;
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.msg.MessageSourceStd;
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 not using Row or RowSet.
 * Not using RowSource makes it much simplier.
 *
 * @author Jack Harich
 */
public class TaskLogic extends MessageSourceStd
    implements BeanActionStart,
    BeanActionClose, MessageListener, EditListener,
    ParamDrivenSupply, ContainerServicesUser,
    TaskLogicFascade {

//---------- Private Fields ------------------------------
// Properties
private String    startMessageName;
private ContainerServices containerServices;
// Internal
private Task          task; // Required
private boolean       started;
private ParamSupplier paramSupplier;
private Param         param;
private Message       startMessage;

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

//---------- MessageSourceStd Abstractions ---------------
public Vector getMessageDefs() {
    return task.getMessageDefs();
}
//---------- BeanActionStart Implementation --------------
public void start() {
    //print(".start() - Entered");
    if (started) {
        // Help the user by putting the focus back on the views
        showViews();
        //print(".start() - Already started");        
        return;
    }
    getParam();      // Late initialization
    initViews();
    // Prepare task
    String className = param.getString("TaskClassName");
    print(".start() - Starting " + className + " with startMessage " + startMessage);    
    task = (Task)GenLib.createInstance(className);
    task.setTaskLogicFascade(this);
    task.setContainerServices(containerServices);
    task.start(startMessage);
    // Present view
    showViews();     // Here to avoid showing while populating
    started = true; 
}
private void initViews() {
    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();
	//	System.out.println("created new view: " + view);
	//	Thread.currentThread().dumpStack();
        dataViews.put(name, view);
        view.setViewName(name);
        view.setEditListener(this);
	Param p = param.getParam(name);
	if(p == null) {
	  System.out.println("there is no param by the name: " + name);
	}
        view.setParam(param.getParam(name));
        view.init();
    }
}
private void showViews() { // Shows the prime views only
    Enumeration enum = dataViews.elements();
    while (enum.hasMoreElements()) {
        DataView view = (DataView)enum.nextElement();
        if (view.isPrimeView()) {
            // Prevent block bug if view is modal
            new Viewer(view).showView();
        }
    }
}
//---------- 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();
    started = false;
    System.gc(); // To fix apparent bug when calling start() second time
}
//---------- MessageListener Implementation --------------
public void processMessage(Message message) {
    String messageName = message.getName();
    //print(".processMessage() - " + messageName + " - " + this);
    if (messageName == startMessageName) {
        startMessage = message;
        start();

    } else {
        task.processMessage(message);
        //print(".processMessage() - Unknown messageName '" +
        //    messageName + "', startMessageName = " + startMessageName);
    }
}
public String[] loadMessageInterests() {
    // Set myMessages
    String[]  myMessages = new String[0];
    if (startMessageName != null) {
        myMessages = new String[] { startMessageName };
    }
    // Add task's messages
    String[] taskMessages = task.loadMessageInterests();
    // Put into one array
    return DataLib.appendStringArray(myMessages, taskMessages);
}
//---------- EditListener Implementation -----------------
  public void processEditEvent(EditEvent evt) {
    //print(".processEditEvent() - " + evt.getEventTypeString());
    int eventType = evt.getEventType();
    
    if (eventType == EditEvent.CLOSE) {
      task.closeWindowRequested(evt.getViewName());
      // *** closeViewRequested(evt.getViewName());
      
    } else if (eventType == EditEvent.COMMAND) {
      task.commandRequested(evt.getViewName(),
			    evt.getCommand().intern());
    } else if (eventType == EditEvent.HELP_REQUESTED) {
      Message msg = new Message("HelpRequested");
      msg.set("HelpId",evt.getHelpId());
      //      print("pEE. - sending message" + msg);
      containerServices.sendMessage(msg);
    } else {
      task.processEditEvent(evt);
    }
  }

  //---------- 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;   
}  
//---------- TaskLogicFascade Implementation -------------
public WidgetSet getWidgetSet(String viewName) {
    return getDataView(viewName).getWidgetSet();
}
public void setVisibleView(String viewName) {
  new Viewer(getDataView(viewName)).showView();
  //  System.out.println("started viewer");
}
public void closeView(String viewName) {
    getDataView(viewName).close();
}
// See BeanActionClose for canClose() and close()

public boolean sendMessage(Message message) {
    return messageRouter.fire(message, task);
}
//---------- 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);
}  
//--- Std
private static void print(String text) {
    System.out.println("TaskLogic" + text);
}
//========== Inner Classes ===============================
private class Viewer implements Runnable {

private DataView view;

public Viewer(DataView view) {
    this.view = view;
}
//---------- Runnable Implementation ---------------------
public void run() {
  //  System.out.println("viewer running");
    try {
        view.setVisible(true);
    } catch(Exception ex) {
        GenLib.exception("TaskLogic.Viewer.run()",
            "Failure in view.setVisible(true)", ex);
    }
}
//---------- Public Methods ------------------------------
public void showView() {
    new Thread(this).start();
}
    
} // End inner class

} // End outer class
