package org.jcon.inspect;

import org.jcon.util.BeanLib;
import org.jcon.util.Hub;
import org.jcon.util.GenLib;
import java.awt.*;
import java.awt.event.*;
import java.util.Vector;
import java.lang.reflect.Method;

import javax.swing.*;

/**
 * Manages method arguments and their text fields.
 * The clipboard is set by:
 *  - MethodInvoker for each invocation.
 *  - Other ???
 *
 * @author Jack Harich
 */
public class MethodArgumentMgr implements KeyListener {

//---------- Private Fields ------------------------------
private Hub       hub;
private Vector    rows; // RowData
private Vector    argValues = new Vector(); // JTextField
private JPanel    mainPanel;
private JPanel    argPanel;
private int       currentRowIndex;

//---------- Initialization ------------------------------
public void setMainPanel(JPanel mainPanel) {
    this.mainPanel = mainPanel;
}
public void setArgPanel(JPanel argPanel) {
    this.argPanel = argPanel;
}
public void setRows(Vector rows) {
    this.rows = rows;
}
public void setHub(Hub hub) {
    this.hub = hub;
}
//---------- KeyListener Implementation ------------------
public void keyTyped(KeyEvent evt) { }
public void keyReleased(KeyEvent evt) { }
public void keyPressed(KeyEvent evt) {
    // Allow cut, copy, paste with Ctrl Shift X, C, V
    if (evt.isControlDown() == false) return;
    if (evt.isShiftDown() == false) return;
    if (! (evt.getSource() instanceof JTextField)) return;

    // Determine which argument field is source
    int argIndex = -1;
    for (int i = 0; i < argValues.size(); i++) {
        if (argValues.elementAt(i) == evt.getSource()) {
            argIndex = i;
            break;
        }
    }
    if (argIndex < 0) {
        print(".keyPressed() - Cannot determine arg field");
        return;
    }
    // Perform hotkey work
    if (evt.getKeyCode() == KeyEvent.VK_X) {
        cutToClipboard(argIndex); // Not implemented
    } else if (evt.getKeyCode() == KeyEvent.VK_C) {
        copyToClipboard(argIndex); // Not implemented
    } else if (evt.getKeyCode() == KeyEvent.VK_V) {
        pasteFromClipboard(argIndex);
    } else if (evt.getKeyCode() == KeyEvent.VK_S) {
        changeArgumentToString(argIndex);
    }
}
//---------- Public Methods ------------------------------
public void populateTextFields(int index) {
    currentRowIndex = index;
    MethodRowData rowData = (MethodRowData)rows.elementAt(index);
    Method method = rowData.getMethod();
    int numberArgs = method.getParameterTypes().length;

    // Change number TextFields shown
    createArgTextFields(numberArgs);

    // Populate textFields from rowData
    for (int i = 0; i < numberArgs; i++) {
        setTextFieldText(i, rowData);
    }
    // Put focus on first field if any
    if (argValues.size() > 0) {
        getArgTextField(0).requestFocus();
    }
}
public void createArgTextFields(int numberArgs) {
    if (numberArgs == argValues.size()) return;

    // Change textFields for editing method arguments
    argValues.removeAllElements();
    GridBagLayout gbl = new GridBagLayout();
    argPanel.setLayout(gbl);
    GridBagConstraints constraints = new GridBagConstraints();
    constraints.fill = GridBagConstraints.HORIZONTAL;
    constraints.gridwidth = GridBagConstraints.REMAINDER;
    constraints.weightx = 100;

    argPanel.removeAll();
    for (int i = 0; i < numberArgs; i++) {
        JTextField textField = new JTextField();
        textField.addKeyListener(this);
        gbl.setConstraints(textField, constraints);
        argPanel.add(textField);
        argValues.addElement(textField);
    }
    mainPanel.validate();
}
// Saves only String arguments. Others already set.
public void saveRowArguments(int rowIndex) {
    MethodRowData rowData = (MethodRowData)rows.elementAt(rowIndex);
    for (int i = 0; i < argValues.size(); i++) {
        MethodArgument argument = rowData.getArgument(i);
        if (argument.isString()) {
            argument.setValue(getArgTextField(i).getText());
        }
    }
}
// *** Later support pasted objects ***
// Get current arguments from rowData
public MethodArgument[] getArguments(int index) {
    saveRowArguments(index);
    MethodRowData rowData = (MethodRowData)rows.elementAt(index);
    return rowData.getArguments();
}
//---------- Private Methods -----------------------------
//----- Clipboard accessors
private void cutToClipboard(int argIndex) {
    print(" - cut not implemented"); // ***
}
private void copyToClipboard(int argIndex) {
    MethodArgument argument = getArgument(argIndex);
    if (argument.isString() ) {
        GenLib.helpfulHint("Control Shift C can only copy a reference to the clipboard.");
        return;
    }
    InspectClipboard clipboard = getClipboard();
    print(" - copy not implemented"); // ***

}
private void pasteFromClipboard(int argIndex) {
    InspectClipboard clipboard = getClipboard();
    // Assert we have something to paste DUPECODE
    if (clipboard.isEmpty() ) {
        print(" - Clipboard empty");
        GenLib.beep();
        return;
    }
    // Assert MethodArgument on clipboard
    Object clipValue = clipboard.getValue();
    if (! (clipValue instanceof MethodArgument)) {
        print(" - Clipboard value is not MethodArgument");
        GenLib.beep();
        return;
    }
    // Assert correct arg type on clipboard
    Class argType = getRowData().getArgType(argIndex);
    MethodArgument argument = (MethodArgument)clipValue;
    if (! (argType.isAssignableFrom(argument.getValue().
            getClass()) )) {
        GenLib.helpfulHint("Clipboard type is not acceptable as argument type.\n"
            + "Clipboard has " + BeanLib.extractFullDisplayTypeName(argument.getValue().getClass() ) + "\n"
            + "Argument type is " + BeanLib.extractFullDisplayTypeName(argType) );
        return;
    }
    // Paste to argument
    MethodRowData rowData = getRowData();
    rowData.setArgument(argIndex, argument);
    // Update textfield and show user wonderful result
    setTextFieldText(argIndex, rowData);
}
//----- Other
// Hot key changes to String and erases contents
private void changeArgumentToString(int argIndex) {
    MethodRowData rowData = getRowData();
    rowData.setArgument(argIndex, new MethodArgument(""));
    setTextFieldText(argIndex, rowData);
}
private InspectClipboard getClipboard() {
    return (InspectClipboard)hub.getNaming().get("Clipboard");
}
// Return that argument for current row
private MethodArgument getArgument(int index) {
    return getRowData().getArgument(index);
}
private MethodRowData getRowData() {
    return (MethodRowData)rows.elementAt(currentRowIndex);
}
private void setTextFieldText(int argIndex, MethodRowData rowData) {
    JTextField textField = getArgTextField(argIndex);
    textField.setText(rowData.getDisplayText(argIndex));
    // Set editable if String, not editable if Reference
    textField.setEditable(rowData.getArgument(argIndex).isString());
    Color bkg = (textField.isEditable() ? Color.white : Color.lightGray);
    textField.setBackground(bkg);
}
private JTextField getArgTextField(int index) {
     return (JTextField)argValues.elementAt(index);
}
//--- Std
private static void print(String text) {
    System.out.println("MethodArgumentMgr" + text);
}

} // End class
