package org.jcon.param.edit;

import org.jcon.ba.system.ItemSystem;
import org.jcon.param.ParamStore;
import org.jcon.util.GenLib;
import org.jcon.ui.MessageBox;
import org.jcon.ui.texteditor.TextEditor;
import org.jcon.ui.texteditor.TextEditorEvent;
import org.jcon.ui.texteditor.TextEditorListener;
import org.jcon.ui.VisualLib;
import org.jcon.ui.WindowLib;
import org.jcon.ui.WindowMgr;
import org.jcon.util.service.ContainerServices;
import org.jcon.param.Param;
import java.awt.*;
import java.awt.event.*;

import javax.swing.Box;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JToggleButton;
import javax.swing.JToolBar;

/**
 * The VIEW for editing a Param. Allows the user to edit
 * Param text directly, with Apply, Save, Revert ability.
 * Also does the controller role currently.
 *
 * @author Jack Harich
 */
public class EditParamView implements
    ActionListener, TextEditorListener, WindowListener {

//---------- Private Fields ------------------------------
private EditParamMgr editParamMgr;
private ParamStore   paramStore;
private Object       groupID;
private Param        param;
private boolean      isAutoView = false;
private JFrame       frame = new JFrame();
private TextEditor   textEditor = new TextEditor();
private ContainerServices containerServices; // of param item

private boolean isDirty;
private boolean isApplyable;
private boolean showingFullText;

private JButton applyBtn  = createButton("Apply", 
    "Apply", "Applies these paramters to the node.", 'A');
private JButton saveBtn   = createButton("Save",
    "Save", "Saves these parameters.", 'S');
private JButton revertBtn = createButton("Revert",
    "Revert", "Loads the old parameters.", 'R');
private JToggleButton fullTextBtn = createToggleButton("Full Text",
    "FullText", "Depress to show full text.", 'F');

private static final String DEFAULT_TITLE = "Param Editor";

//---------- Initialization ------------------------------
public EditParamView() {
    // frame
    WindowMgr.registerFrame(frame);
    frame.setTitle(DEFAULT_TITLE);
    frame.setBackground(Color.lightGray);
    frame.addWindowListener(this);
    frame.setSize(500, 600);
    WindowLib.position(frame, WindowLib.STRETCH_RIGHT);
    // toolBar
    JToolBar toolBar = textEditor.getToolBar();
    toolBar.add(Box.createHorizontalStrut(10)); // Gap
    toolBar.add(applyBtn);
    toolBar.add(saveBtn);
    toolBar.add(revertBtn);
    // *** no fixed width toolBar.add(new Label(" ")); // Spacer
    toolBar.add(fullTextBtn);
    frame.getContentPane().add("North", toolBar);
    // textEditor
    frame.getContentPane().add("Center", textEditor.getMainComponent());
    textEditor.addTextEditorListener(this);
    // Misc
    refreshEditState();
}
//---------- ActionListener Implementation ---------------
public void actionPerformed(ActionEvent evt) {
    String command = evt.getActionCommand().intern();
    //print(".actionPerformed() - commend = '" + command + "'");

    if (command == "SaveYes" || command == "SaveNo") {
        processSaveDialogResponse(command);
    } else if (command == "Apply") {
        applyParam();
    } else if (command == "Save") {
        saveParam();
    } else if (command == "Revert") {
        revertParam();
    } else if (command == "FullText") {
        fullTextRequested(fullTextBtn.isSelected());        
    }
}
//---------- TextEditorListener Implementation -----------
public void textEditorEvented(TextEditorEvent evt) {
    int eventType = evt.getEventType();
    
    if (eventType == TextEditorEvent.TO_DIRTY) {
        //print(".textEditorEvented() - TO_DIRTY, isApplyable = " + isApplyable); 
        isApplyable = true;
        isDirty = true;
        refreshEditState();
        
    } else if (eventType == TextEditorEvent.CHANGED) {
        if (! isApplyable || ! isDirty) {
            isApplyable = true;
            isDirty = true;
            refreshEditState();
        }
    }
}
//---------- WindowListener Implementatons ---------------
public void windowClosing(WindowEvent evt) {
    // User clicked on X or chose window Close
    close();
}
public void windowClosed(WindowEvent evt) { }
public void windowDeiconified(WindowEvent evt) { }
public void windowIconified(WindowEvent evt) { }
public void windowOpened(WindowEvent evt) { }
public void windowActivated(WindowEvent evt) {  }
public void windowDeactivated(WindowEvent evt) { }

//---------- Properties ----------------------------------
//----- param
public void setParam(Param param) {
    this.param = param;
    initFullTextState();
    if (param != null) {
        refreshText();
        // Set title
        String resourceName = param.getAccessor().getResourceName();
        String windowName = null;
        if (isAutoView) {
            windowName = "Auto Param Editor";
        } else {
            windowName = "Param Editor";
        }
        frame.setTitle(resourceName + " - " + windowName);

    } else {
        textEditor.setText(null);
        frame.setTitle(DEFAULT_TITLE);
    }
    isApplyable = false;
    setToNotDirty();
    refreshEditState();
}
// This is a subsystem that could have its own class for clarity
private void initFullTextState() { // *******************
    fullTextBtn.setSelected(false);
    showingFullText = false;
    if (param == null) {
        fullTextBtn.setEnabled(false);
    } else if (param.hasFullText()) {
        fullTextBtn.setEnabled(true);
    } else {
        fullTextBtn.setEnabled(false);
    }
    //print(".initFullTextState() - hasFullText is " + param.hasFullText());
}
public Param getParam() {
    return param;
}
//----- groupID
public void setGroupID(Object groupID) {
    this.groupID = groupID;
}
public Object getGroupID() {
    return groupID;
}
//----- isAutoView
public void setAutoView(boolean isAutoView) {
    this.isAutoView = isAutoView;
}
public boolean isAutoView() {
    return isAutoView;
}
//----- visible
public void setVisible(boolean isVisible) {
    frame.setVisible(isVisible);
}
public boolean isVisible() {
    return frame.isVisible();    
}
//----- Other
public void setContainerServices(ContainerServices containerServices) {
    this.containerServices = containerServices;
}
public void setEditParamMgr(EditParamMgr editParamMgr) {
    this.editParamMgr = editParamMgr;
}
public boolean isDirty() {
    return isDirty;
}
public void setParamStore(ParamStore paramStore) {
    this.paramStore = paramStore;
}
//---------- Public Methods ------------------------------
public void requestFocus() {
    frame.requestFocus();
}
public void close() {
    if (isDirty()) {
        presentDirtyDialog();
    } else {
        completeCloseRequested();
    }
}
//---------- Package Methods -----------------------------
private void presentDirtyDialog() {
    frame.requestFocus();
    MessageBox box = new MessageBox(this);
    box.setTitle("Parameters");
    box.addChoice("Yes", "SaveYes");
    box.addChoice("No", "SaveNo");
    box.setCloseWindowAllowed(false);
    box.ask("These parameters have been changed.\n\n" +
        "Save changes?");
}
//---------- Private Methods -----------------------------
//----- Param mutators
private void applyParam() {
    // See dev/ParamEditor applyParam() for old version
    Param newParam = param.cloneUsingNewText(textEditor.getText());
    newParam = ItemSystem.buildParam(newParam, containerServices);
    boolean success = param.applyNewParam(newParam);
    if (success) {
        param = newParam; // <-----<<<
        // Change button state
        isApplyable = false;
        refreshEditState();
    }
    editParamMgr.fireParamAppliedEvent(this, param, success);
}
private void saveParam() {
    String text = textEditor.getText();
    if (paramStore.writeParam(param, text) == true) {
        // Change button state
        setToNotDirty();
        refreshEditState();
    }
}
private void revertParam() {
    //print(".revertParam() - param.getAccessor() = " + param.getAccessor());
    // Put old param state into my param
    Param oldParam = paramStore.readParam(param.getAccessor());
    oldParam = ItemSystem.buildParam(oldParam, containerServices);
    // Set ParamDriven since the oldParam was created, not cloned
    oldParam.setParamDriven(param.getParamDriven()); 
    param.copy(oldParam);
    // Show result
    refreshText();
    // Change button state
    setToNotDirty();
    isApplyable = true;
    refreshEditState();
}
// Only called if enabled and therefore fullText available
private void fullTextRequested(boolean isFullTextSelected) {
    showingFullText = isFullTextSelected;
    refreshText();
    refreshEditState();
}
//----- Other
private void refreshText() {
    if (showingFullText) {
        textEditor.setText(param.getFullText());
    } else {
        textEditor.setText(param.getText());
    }
}
private void setToNotDirty() {
    textEditor.setDirty(false); 
    isDirty = false;
}    
private void processSaveDialogResponse(String command) {
    // Remember this is a result of a close() request
    if (command == "SaveYes") saveParam();
    completeCloseRequested();
}
private void completeCloseRequested() {
    if (isAutoView) {
        setVisible(false);
    } else {
        frame.dispose();
    }
    editParamMgr.viewClosed(this);
}
private void refreshEditState() {
    //print(".refreshEditState() - showingFullText = " + showingFullText);
    if (showingFullText) {
        applyBtn.setEnabled(false);
        saveBtn.setEnabled(false);
        revertBtn.setEnabled(false);
        textEditor.setEditable(false);
        textEditor.setEnabled(true);
    } else {
        applyBtn.setEnabled(isApplyable);
        saveBtn.setEnabled(isDirty());
        revertBtn.setEnabled(isDirty());
        textEditor.setEditable(true);
        textEditor.setEnabled(param != null ? true : false);
        fullTextBtn.setEnabled(! isDirty());
        
        if (param == null) {
            fullTextBtn.setEnabled(false);
        } else if (! param.hasFullText()) {
            fullTextBtn.setEnabled(false);
        } else {
            fullTextBtn.setEnabled(true);
        }
    }
}
private JButton createButton(String text,
        String command, String toolTip, char mnemonic) {
    JButton button = VisualLib.createCompactButton(
        text, command, toolTip);
    button.addActionListener(this);
    if (mnemonic != '\u0000') button.setMnemonic(mnemonic);
    return button;
}
private JToggleButton createToggleButton(String text,
        String command, String toolTip, char mnemonic) {
    JToggleButton button = new JToggleButton(text);
    button.setActionCommand(command);
    if (toolTip != null) button.setToolTipText(toolTip);
    button.addActionListener(this);
    if (mnemonic != '\u0000') button.setMnemonic(mnemonic);
    return button;
}
//--- Std
private static void print(String text) {
    System.out.println("EditParamView" + text);
}

} // End class
