/*******************************************************************************
 * Copyright (c) 2010 Oak Ridge National Laboratory.
 * 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
 ******************************************************************************/
package org.csstudio.opibuilder.widgetActions;

import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.logging.Level;

import org.csstudio.opibuilder.OPIBuilderPlugin;
import org.csstudio.opibuilder.editparts.AbstractBaseEditPart;
import org.csstudio.opibuilder.editparts.DisplayEditpart;
import org.csstudio.opibuilder.script.ScriptService;
import org.csstudio.opibuilder.script.ScriptStoreFactory;
import org.csstudio.opibuilder.util.ConsoleService;
import org.csstudio.opibuilder.util.ResourceUtil;
import org.csstudio.opibuilder.widgetActions.WidgetActionFactory.ActionType;
import org.csstudio.ui.util.thread.UIBundlingThread;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.gef.GraphicalViewer;
import org.eclipse.swt.widgets.Display;
import org.python.core.Py;
import org.python.core.PyCode;
import org.python.core.PyObject;
import org.python.core.PyString;
import org.python.core.PyStringMap;
import org.python.core.PySystemState;
import org.python.util.PythonInterpreter;

/**The action executing python script.
 * @author Xihui Chen
 *
 */
public class ExecutePythonScriptAction extends AbstractExecuteScriptAction {

    private PyCode code;
    private PythonInterpreter interp;
    private PySystemState state;
    private DisplayEditpart displayEditpart;
    private AbstractBaseEditPart widgetEditPart;
    
    @Override
    public ActionType getActionType() {
        return ActionType.EXECUTE_PYTHONSCRIPT;
    }

    @Override
    public void run() {
        if(code == null){
            try {
                ScriptStoreFactory.initPythonInterpreter();
            } catch (Exception e) {
                final String message = "Failed to initialize PythonInterpreter";
                OPIBuilderPlugin.getLogger().log(Level.WARNING, message, e);
                ConsoleService.getInstance().writeError(message + "\n" + e); //$NON-NLS-1$
            }
            //read file
            IPath absolutePath = getAbsolutePath();
            PySystemState state = Py.getSystemState();

            //Add the path of script to python module search path
            if(!isEmbedded() && absolutePath != null && !absolutePath.isEmpty()){
                //If it is a workspace file.
                if(ResourceUtil.isExistingWorkspaceFile(absolutePath)){
                    IPath folderPath = absolutePath.removeLastSegments(1);
                    String sysLocation = ResourceUtil.workspacePathToSysPath(folderPath).toOSString();
                    state.path.append(new PyString(sysLocation));
                }else if(ResourceUtil.isExistingLocalFile(absolutePath)){
                    IPath folderPath = absolutePath.removeLastSegments(1);
                    state.path.append(new PyString(folderPath.toOSString()));
                }
            }

            interp = PythonInterpreter.threadLocalStateInterpreter(state.path.getDict());

            GraphicalViewer viewer = getWidgetModel().getRootDisplayModel().getViewer();
            if(viewer != null){
                Object obj = viewer.getEditPartRegistry().get(getWidgetModel());
                if(obj != null && obj instanceof AbstractBaseEditPart){
                    displayEditpart = (DisplayEditpart)(viewer.getContents());
                    widgetEditPart = (AbstractBaseEditPart)obj;
                }
            }
        }

        Job job = new Job("Execute Python Script") {

            @Override
            protected IStatus run(IProgressMonitor monitor) {
                String taskName = isEmbedded()?"Execute Python Script" :
                    "Connecting to " + getAbsolutePath();
                monitor.beginTask(taskName,
                        IProgressMonitor.UNKNOWN);
                runTask();
                monitor.done();
                return Status.OK_STATUS;
            }
        };
        job.setUser(true);
        job.schedule();
    }

    public void runTask() {
        Display display = getWidgetModel().getRootDisplayModel().getViewer().getControl().getDisplay();

        try {
            if(code == null){

                //compile
                if(isEmbedded())
                    code = interp.compile(getScriptText());
                else{
                    InputStream inputStream = getInputStream();
                    code = interp.compile(new InputStreamReader(inputStream));
                    inputStream.close();
                }
            }


            UIBundlingThread.getInstance().addRunnable(display, new Runnable() {

                @Override
                public void run() {

                        try {
                            interp.set(ScriptService.WIDGET, widgetEditPart);
                            interp.set(ScriptService.DISPLAY, displayEditpart);
                            interp.exec(code);
                        } catch (Exception e) {
                            final String message =  "Error exists in script " + getPath();
                            OPIBuilderPlugin.getLogger().log(Level.WARNING, message, e);
                            ConsoleService.getInstance().writeError(message + "\n" + e); //$NON-NLS-1$
                        }
                }
            });
        } catch (Exception e) {
            final String message = "Failed to execute Python Script: " + getPath();
            OPIBuilderPlugin.getLogger().log(Level.WARNING, message, e);
            ConsoleService.getInstance().writeError(message + "\n" + e); //$NON-NLS-1$
        }
    }


    @Override
    protected String getFileExtension() {
        return ScriptService.PY;
    }

    @Override
    protected String getScriptHeader() {
        return ScriptService.DEFAULT_PYTHONSCRIPT_HEADER;
    }

    @Override
    public void dispose() {
        if (interp != null) {
            PyObject o = interp.getLocals();
            if (o != null && o instanceof PyStringMap) {
                ((PyStringMap)o).clear();
            }
            o = state.getDict();
            if (o != null && o instanceof PyStringMap) {
                ((PyStringMap)o).clear();
            }
            state.close();
            state.cleanup();
            interp.close();
            interp.cleanup();
            interp = null;
            state = null;
        }
        super.dispose();
    }

}

@@ -1406,35 +1406,8 @@
 ay;%0A
-import org.python.core.Py;%0A
 impo
@@ -1433,16 +1433,16 @@
 PyCode;%0A
+
 import o
@@ -1823,16 +1823,21 @@
 r interp
+reter
 ;%0A    pr
@@ -1961,13 +1961,9 @@
 rt;%0A
-    
 %0A
+
     
@@ -2600,36 +2600,22 @@
     
-PySystemState state = Py.get
+state = new Py
 Syst
@@ -3413,18 +3413,27 @@
   interp
- =
+reter = new
  PythonI
@@ -3446,57 +3446,19 @@
 eter
-.threadLocalStateInterpreter(state.path.getDict()
+(null,state
 );%0A%0A
@@ -4726,32 +4726,37 @@
    code = interp
+reter
 .compile(getScri
@@ -4885,16 +4885,21 @@
 = interp
+reter
 .compile
@@ -5212,32 +5212,37 @@
           interp
+reter
 .set(ScriptServi
@@ -5303,16 +5303,21 @@
   interp
+reter
 .set(Scr
@@ -5388,16 +5388,21 @@
   interp
+reter
 .exec(co
@@ -6367,16 +6367,21 @@
  (interp
+reter
  != null
@@ -6415,16 +6415,21 @@
 = interp
+reter
 .getLoca
@@ -6767,16 +6767,21 @@
   interp
+reter
 .close()
@@ -6800,16 +6800,21 @@
   interp
+reter
 .cleanup
@@ -6835,16 +6835,21 @@
   interp
+reter
  = null;

Fix ExecutePythonScriptAction NPE and use separate interp.