/*******************************************************************************
* Copyright (c) 2006 IONA Technologies PLC
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
* 
* Contributors:
*     IONA Technologies PLC - initial API and implementation
*******************************************************************************/
package org.eclipse.stp.sc.common.wizards;

import java.util.Map;

import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Table;
import org.eclipse.ui.PlatformUI;



/**
 * superclass of all wizard pages intended to enforce coherent and consistant architectures and life cycle
 *  behaviours
 * This class propose a standard mechanism for:
 * <br>- input validations
 * <br>- data model management (loading & commiting)
 * <br>- nav controls state updates/refresh mechanisms
 * <br>- standards listeners.
 */
public abstract class AbstractScWizardPage extends WizardPage {
    //private static final LoggingProxy LOG = LoggingProxy.getlogger(AbstractScWizardPage.class);
    protected AbstractScWizard parentWizard;
    private boolean doValidationAndUpdate;
    private String helpContextId;
    
    

    /**
     * new standard constructor allowing to keep a reference of the parent wizard for data management
     * @param aParentWizard the parent wizard, controling the necessary temporary data model
     * @param aPageName an internal reference name for the page
     * @param aHelpContextId an optional context ID for infopop help support
     */
    public AbstractScWizardPage(AbstractScWizard aParentWizard, String aPageName, String aHelpContextId) {
        super(aPageName);
        parentWizard = aParentWizard;
        helpContextId = aHelpContextId;
        
        setDoValidationAndUpdate(true);
        setPageComplete(false);
    }

    /**
     * validate the pages inputs in sequence and exits at the 1st failure, after setting the
     *  appropriate message/error
     * @return true if all users inputs are valid, false otherwise
     */
    protected abstract boolean validateInputs();

    /**
     * initializes the page controls base on the current data model from the parent wizard.
     * <br> note that implementations of this method should not worry about initial validations
     * and messaging as it will be done anyway after the call to this method
     * @param data the data model handled by the current wizard
     */
    public abstract void initializeFromData(Map<String, Object> data) throws Exception;

    /**
     * update the data model of the parent wizard with the controls inputs of the page
     * initializes the page controls base on
     * @param data the data model handled by the current wizard
     */
    public abstract void applyToData(Map<String, Object> data) throws Exception;

    public final Map<String, Object> getWizardData() {
        return (parentWizard == null) ? null : parentWizard.getWizardData();
    }

    /**
     * perform every required initialization before displaying the page
     * @throws Exception
     */
    public final void initializeBeforeDisplay() throws Exception {
        setDoValidationAndUpdate(false);
        initializeFromData(parentWizard.getWizardData());
        setDoValidationAndUpdate(true);
        updatePageState();
    }

    /**
     * performs an overall validation and GUI update of the page
     */
    public final void updatePageState() {
        if (isDoValidationAndUpdate()) {
            setErrorMessage(null);
            setMessage(null);
            setPageComplete(validateInputs());
        }
    }

    /**
     * This adds a modifyListener to a editable cell due to limitations in SWT tableviewers
     *
     * @param tv        The TableViewer holding the CellEditor
     * @param row       The row needed to be listening to
     * @param column    The table column which is editable
     * @param isNumeric true for checking numeric values only
     *
     * CiaranOC Review - There's problems here with cut and paste so till I
     * figure out how to disable pasting on a text editor I'll use the key listener
     */

    //    protected void addCellModifyListener(final TableViewer tv,
    //                                         final int row, 
    //                                         int column,
    //                                         boolean allowDecimal) {
    //        addCellModifyListener(tv, row, column);
    //        final TextCellEditor ce = (TextCellEditor)tv.getCellEditors()[column];
    //        
    //        /* Allows for a dot to be added if a float. Use an array to get over 
    //         * using a final variable inside method
    //         */
    //        final String[] check = new String[1];
    //        if (!allowDecimal) {
    //            check[0] = "0123456789";
    //        } else {
    //            check[0] = "0123456789.";
    //        }
    //        ((Text)ce.getControl()).addVerifyListener(new VerifyListener() {
    //            
    //            public void verifyText(VerifyEvent e) {
    //                if (tv.getTable().getSelectionIndex() == row) {
    //                    LOG.info("verifyText :: row = " + row + " text = " + e.text);
    //                    e.doit = check[0].indexOf(e.text) >= 0;
    //                    if (e.doit) {
    //                        LOG.info("Setting the value before updatePageState = " + e.text);
    //                        tv.getTable().getItem(row).setText(1, e.text);
    //                        LOG.info("Value set before updatePageState = " + e.text);
    //                        updatePageState();
    //                    } else {
    //                        LOG.info("Its going into the else >>>>>>>> ");
    //                        setErrorMessage(mNumericMessage);
    //                    }
    //                }
    //            }
    //        });
    //    }

    /**
     * This adds a modifyListener to a editable cell due to limitations in SWT tableviewers
     *
     * @param tv        The TableViewer holding the CellEditor
     * @param row       The row needed to be listening to
     * @param column    The table column which is editable
     */
    /*protected void addCellModifyListener(final TableViewer tv, final int row, int column) {

        final TextCellEditor ce = (TextCellEditor)tv.getCellEditors()[column];
        
        ce.getControl().addKeyListener(new KeyListener() {
            public void keyReleased(KeyEvent e) {
                if (tv.getTable().getSelectionIndex() == row) {
                    tv.getTable().getItem(row).setText(1, (String)ce.getValue());
                    updatePageState();
                }
            }

            public void keyPressed(KeyEvent e) {
            }
        });
    }*/

    /**
     * gets the page current help context ID
     * @return the page current context ID
     */
    protected String getHelpContextId() {
        return helpContextId;
    }

    /**
     * sets a new help context ID for the page
     * @param a new context ID for the page
     */
    protected void setHelpContextId(String aHelpContextId) {
        this.helpContextId = aHelpContextId;
        applyHelpContextID();
    }

    /**
     * extends the initial implementation by registring the help
     * @param newControl
     * @see org.eclipse.jface.dialogs.DialogPage#setControl(org.eclipse.swt.widgets.Control)
     */
    protected void setControl(Control newControl) {
        super.setControl(newControl);
        applyHelpContextID();
    }

    /**
     * apply the help context id to the page if the page is in an appropriate state
     */
    private void applyHelpContextID() {
        if ((getControl() != null) && (helpContextId != null) && (helpContextId.trim().length() > 0)) {
            PlatformUI.getWorkbench().getHelpSystem().setHelp(getControl(), helpContextId);
        }
    }

    public void setDoValidationAndUpdate(boolean validationAndUpdate) {
        doValidationAndUpdate = validationAndUpdate;
    }

    public boolean isDoValidationAndUpdate() {
        return doValidationAndUpdate;
    }

    /**
     * ???? now idea of what it's for...
     */
    public final class TableSelectionListener extends SelectionAdapter {
        private Table mTable;

        public TableSelectionListener(Table table) {
            mTable = table;
        }

        public void widgetSelected(SelectionEvent e) {
            mTable.deselect(mTable.getSelectionIndex());
        }
    }

    /**
     * provides real time validation and GUI update on list, combo
     * and button selection events
     */
    public final class UpdatePageStatusSelectionListener extends SelectionAdapter {
        public void widgetSelected(SelectionEvent e) {
            updatePageState();
        }
    }

    /**
     * provides real time validation and GUI update on text input event
     */
    public final class UpdatePageStatusKeyPressedListener extends KeyAdapter {
        public void keyReleased(KeyEvent e) {
            updatePageState();
        }
    }

    /**
     * provides real time validation and GUI update on text modification event
     */
    public final class UpdatePageStatusModifyListener implements ModifyListener {
        public void modifyText(ModifyEvent e) {
            updatePageState();
        }
    }

    /**
     * provides real time validation and GUI update on mouse events
     */
    public final class UpdatePageStatusMouseListener extends MouseAdapter {
        public void mouseUp(MouseEvent e) {
            updatePageState();
        }
    }
}
