package org.jcon.inspect;

import org.jcon.ui.VisualLib;
import org.jcon.util.GenLib;
import org.jcon.util.Hub;
import java.awt.Rectangle;
import java.beans.BeanInfo;
import java.beans.Introspector; 
import java.beans.IntrospectionException;
import java.util.Vector;

/**
 * A property and method sheet style inspector that allows
 * visual bean inspection and manipulation. Many features.
 * Subsystem entry point.
 *
 * *** Note - Not completely reusable. Need to add properties:
 * - Default title, which is "Auto Inspector" now
 * - Use Messages tab, which is aways true now (or custom tab)
 *
 * @author Jack Harich
 */
public class Inspector implements Cloneable {

//---------- Private Fields ------------------------------
private static InspectClipboard clipboard = new InspectClipboard();

private Hub      hub = new Hub(); // For internal collaboration
private View     view = new View(this);
private Machine  machine = new Machine();

private InspectorController controller;
private Object   instance;
private String   instanceName;
private boolean  autoClose = true;

//---------- Initialization ------------------------------
public Inspector() {
    view.setHub(hub);
    machine.setHub(hub);
    machine.setInspector(this);

    // Clipboard is available to all inspectors
    if (! hub.getNaming().containsKey("Clipboard") ) {
        hub.getNaming().set("Clipboard", clipboard);
    }
}
/**
 * Provides a handy one line call to open an Inspector on
 * an instance. The @param name is currently arbitrary.
 */
public Inspector(Object instance, String name) {
    this();
    setInstance(instance, name);
    setVisible(true);
}
/**
 * Unit test with command options. Option 1 is className,
 * option 2 is instanceName.  java org.jcon.inspect.Inspector
 */
public static void main(String args[]) {
    String className = "org.jcon.inspect.TestBean";
    if (args.length > 0) className = args[0];

    String testName = "InstanceName";
    if (args.length > 1) testName = args[1];

    VisualLib.installLookAndFeel();

    Object testInstance = GenLib.createInstance(className);
    print(".main() - Preparing Inspector for " + className);
    new Inspector(testInstance, testName);
}
//---------- Superclass Overrides ------------------------
/**
 * Performs a shallow copy, with the exception that the
 * view is not visible. This allows the client to
 * initialized the clone before showing it.
 *
 * Note the instance being inspected is NOT cloned.
 */
public synchronized Object clone() {
    Inspector inspector = new Inspector();
    inspector.setInstance(instance, instanceName);
    Rectangle r = view.getBounds();
    inspector.setBounds(r.x, r.y, r.width, r.height);
    inspector.view.setSplit(view.isSplit());
    return inspector;
}
//---------- Properties ----------------------------------
//----- Visible
public void setVisible(boolean visible) {
    //print(".setVisible() - Entered, visible = " + visible);
    view.setVisible(visible);
}
public boolean isVisible() {
    return view.isVisible();
}
//----- Bounds
public Rectangle getBounds() {
    return view.getBounds();
}
public void setBounds(int x, int y, int width, int height) {
    view.setBounds(x, y, width, height);
}
public void setBounds(Rectangle r) {
    view.setBounds(r.x, r.y, r.width, r.height);
}
//----- AutoClose
/**
 * If AutoClose is true then the inspector will close itself
 * automatically and no InspectorListener.windowClosing()
 * will be fired. Otherwise the opposite will occur, and the
 * client should handle the close or hide manually.
 */
public void setAutoClose(boolean autoClose) {
    this.autoClose = autoClose;
}
public boolean isAutoClose() {
    return autoClose;
}
//----- WindowPosition
public void setWindowPosition(int position) {
    view.setWindowPosition(position);
}
//----- Other
public Object getInstance() {
    return instance;
}
public String getInstanceName() {
    return instanceName;
}
public void setController(InspectorController controller) {
    this.controller = controller;
}
//---------- Public Methods ------------------------------
/**
 * Sets the instance being inspected. Has no effect on
 * other properties such as exploration path, view.
 *
 * Designed to allow a controller to use an Inspector to
 * show/inspect the currently selected instance. Also used
 * internally for explore, return, clone.
 */
public void setInstance(Object instance, String name) {
    this.instance = instance;
    this.instanceName = name;
    view.setTitle(name);
    view.setClassName(instance.getClass().getName());
    // Pass BeanInfo to sheets
    try {
        // Search upward stopping before Object
        BeanInfo info = Introspector.getBeanInfo(
            instance.getClass(), Object.class);
        view.loadBeanInfo(info, instance);

    } catch(IntrospectionException ex) {
        print(".setInstance()\n");
        ex.printStackTrace();
    }
}
/**
 * Call this when closing an inspector. It cannot be used
 * again after closing.
 */
public void close() {
    view.close();
}
public void requestFocus() {
    //print(".requestFocus() - Entered");
    view.requestFocus();
}
//---------- Package Methods -----------------------------
// Called by view upon windowClosing()
void viewWindowClosing() {
    if (autoClose) {
        view.close();
    } else if (controller != null) {
        controller.inspectorClosingRequested(this);
    }
}
// Called by view on request from MessageSheet
Vector loadSignalChain(String eventName, Object instance) {
    if (controller != null) {
        return controller.loadSignalChain(this, eventName, instance);
    } else {
        return null;
    }
}
//---------- Private Methods -----------------------------
//--- Std
private static void print(String text) {
    System.out.println("Inspector" + text);
}

} // End class