/**
 * Copyright (c) 2005-2012 by Appcelerator, Inc. All Rights Reserved.
 * Licensed under the terms of the Eclipse Public License (EPL).
 * Please see the license.txt included with this distribution for details.
 * Any modifications to this file must keep this entire header intact.
 */
/*
 * Created on Sep 15, 2004
 *
 * @author Fabio Zadrozny
 */
package org.python.pydev.editor.actions.refactoring;

import java.io.File;
import java.lang.reflect.InvocationTargetException;

import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.actions.WorkspaceModifyOperation;
import org.eclipse.ui.progress.UIJob;
import org.python.pydev.core.IPythonNature;
import org.python.pydev.core.MisconfigurationException;
import org.python.pydev.core.docutils.PySelection;
import org.python.pydev.core.log.Log;
import org.python.pydev.editor.PyEdit;
import org.python.pydev.editor.actions.PyAction;
import org.python.pydev.editor.refactoring.AbstractPyRefactoring;
import org.python.pydev.editor.refactoring.IPyRefactoring;
import org.python.pydev.editor.refactoring.RefactoringRequest;

/**
 * @author Fabio Zadrozny
 */
public abstract class PyRefactorAction extends PyAction {

    protected IWorkbenchWindow workbenchWindow;

    private final class Operation extends WorkspaceModifyOperation {

        /**
         * The action to be performed
         */
        private final IAction action;

        public Operation(IAction action) {
            super();
            this.action = action;
        }

        /**
         * Execute the actual refactoring (needs to ask for user input if not using the default
         * refactoring cycle)
         */
        @Override
        protected void execute(IProgressMonitor monitor) throws CoreException, InvocationTargetException,
                InterruptedException {

            try {
                monitor.beginTask("Refactor", IProgressMonitor.UNKNOWN);
                perform(action, monitor);
                monitor.done();
            } catch (Exception e) {
                Log.log(e);
            }

        }
    }

    public RefactoringRequest getRefactoringRequest() throws MisconfigurationException {
        return getRefactoringRequest(null);
    }

    /**
     * This is the refactoring request
     */
    protected volatile RefactoringRequest request;

    /**
     * @return the refactoring request (it is created and cached if still not available)
     * @throws MisconfigurationException 
     */
    public RefactoringRequest getRefactoringRequest(IProgressMonitor monitor) throws MisconfigurationException {
        if (request == null) {
            //testing first with whole lines.
            PyEdit pyEdit = getPyEdit(); //may not be available in tests, that's why it is important to be able to operate without it
            request = createRefactoringRequest(monitor, pyEdit, ps);
        }
        request.pushMonitor(monitor);
        return request;
    }

    /**
     * @param operation the operation we're doing (may be null)
     * @param pyEdit the editor from where we'll get the info
     * @throws MisconfigurationException 
     */
    public static RefactoringRequest createRefactoringRequest(IProgressMonitor monitor, PyEdit pyEdit, PySelection ps)
            throws MisconfigurationException {
        File file = pyEdit.getEditorFile();
        IPythonNature nature = pyEdit.getPythonNature();

        RefactoringRequest req = new RefactoringRequest(file, ps, monitor, nature, pyEdit);
        return req;

    }

    /**
     * Checks if the refactoring preconditions are met.
     * @param request the request for the refactoring
     * @param pyRefactoring the engine to do the refactoring
     * @return true if they are ok and false otherwise
     */
    protected boolean areRefactorPreconditionsOK(RefactoringRequest request, IPyRefactoring pyRefactoring) {
        workbenchWindow = PlatformUI.getWorkbench().getActiveWorkbenchWindow();

        IEditorPart[] dirtyEditors = workbenchWindow.getActivePage().getDirtyEditors();

        boolean saveEditors = false;
        if (dirtyEditors.length > 0) {
            saveEditors = MessageDialog.openQuestion(getPyEditShell(), "Save All?",
                    "All the editors must be saved to make this operation.\nIs it ok to save them?");
            if (saveEditors == false) {
                return false;
            }
        }

        if (saveEditors) {
            boolean editorsSaved = workbenchWindow.getActivePage().saveAllEditors(false);
            if (!editorsSaved) {
                return false;
            }
        }
        return true;
    }

    /**
     * This is the current text selection
     */
    protected PySelection ps;

    /**
     * Actually executes this action.
     * 
     * Checks preconditions... if 
     */
    @Override
    public void run(final IAction action) {
        // Select from text editor
        request = null; //clear the cache from previous runs
        ps = new PySelection(getTextEditor());

        RefactoringRequest req;
        try {
            req = getRefactoringRequest();
        } catch (MisconfigurationException e2) {
            Log.log(e2);
            return;
        }
        IPyRefactoring pyRefactoring = AbstractPyRefactoring.getPyRefactoring();
        if (areRefactorPreconditionsOK(req, pyRefactoring) == false) {
            return;
        }

        UIJob job = new UIJob("Performing: " + this.getClass().getName()) {

            @Override
            public IStatus runInUIThread(final IProgressMonitor monitor) {
                try {
                    Operation o = new Operation(action);
                    o.execute(monitor);
                } catch (Exception e) {
                    Log.log(e);
                }
                return Status.OK_STATUS;
            }

        };
        job.setSystem(true);
        job.schedule();
    }

    /**
     * @return a shell from the PyEdit
     */
    protected Shell getPyEditShell() {
        return getPyEdit().getSite().getShell();
    }

    /**
     * This is the method that should be actually overridden to perform the refactoring action.
     * 
     * @param action the action to be performed 
     * @param monitor the monitor for the operation
     * @return the status returned by the server for the refactoring.
     * @throws Exception
     */
    protected abstract String perform(IAction action, IProgressMonitor monitor) throws Exception;

}