/*
 * Copyright (c) 2005, Stanford University. All rights reserved.
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met: 
 *  - Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *  - Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *  - Neither the name of the Stanford University nor the names of its
 *    contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */     

/*      
 * Created on June 12, 2006  -- modified version of RunPymolThread.java
 * Original author: Christopher Bruns, Mark Friedrichs
 */     

package org.simtk.isimsu;

import java.io.*;
import java.util.*;
        
import org.simtk.gui.*;          
        
/**
 *
  * @author Christopher Bruns
  *
  * class to manage the running of the program Pymol on a molecule
 */
public class RunPymolThread extends JarDefinedExecutableThread
implements MonitoredProcess
{
    // ISIMTask pymolTask;
    ISIMWrapper isimWrapper;
    APBSParameters pymolParameters;
    ISIMStepParameters stepParameters;
    int displayFileType;
    
    // Constructor
    RunPymolThread(ISIMStepParameters s, APBSParameters p, ISIMWrapper isimWrapper) {
        stepParameters = s;
        pymolParameters = p;
        this.isimWrapper = isimWrapper;
    }
    
    public void run() {
 
    	String methodName = "RunPymolThread ";
        isimWrapper.appendToLog( methodName + "Starting Pymol task...\n");

        ISIMTask task = stepParameters.task;

        // Don't do anything if it appears that someone else is already doing this task
        if (task.isRunning()) return;

        String pymolDirectory       = "dir_pymol";
        String pymolExecutableName  = "pymol_arguments";
        isimWrapper.appendToLog( methodName + "Unpacking Pymol executable from \n   <" + pymolDirectory + "/" +
                                 pymolExecutableName + "> to\n    <" + stepParameters.programDirectory + ">\n");

        Vector initialArgs = new Vector();
        try {
        	initialArgs = unpackExecutable( pymolDirectory, pymolExecutableName,
        			                        stepParameters.programDirectory);
        } catch (IOException exc) {
        	reportFailure(exc, "error unpacking Pymol executable");
        	return;
        }
        isimWrapper.appendToLog( methodName + " Unpacked Pymol executable." );

        // get OS (Windows, Linux, Mac )
        
        String osName = ExternalProcessManager.getOsType();
        isimWrapper.appendToLog( methodName + " Osname=" + osName + "\n" );
        
        // get location of Pymol (from muffin, generic locations on machine or as a
        // last resort from the user
        // if not found, then bail out after loggin message
        
        GetPymolLocation  getPymolLocation = new GetPymolLocation( isimWrapper, isimWrapper.getLogDialog() );
        String pymolLocation               = getPymolLocation.getPathToPymolExecutable( osName );
         
        if( pymolLocation == null ){
        	isimWrapper.appendToLog( methodName + "Pymol path unavailable." );
        	return;
        }
        String pymolEnvironmentPath   = getPymolLocation.getPymolEnvironmentPath( pymolLocation, osName );
        String pythonEnvironmentPath   = getPymolLocation.getPythonEnvironmentPath( pymolLocation, osName );
        
        isimWrapper.appendToLog( methodName + "Pymol executable   path=<" + pymolLocation + ">\n" );
        isimWrapper.appendToLog( methodName + "Pymol environment  path=<" + pymolEnvironmentPath + ">\n" );
        isimWrapper.appendToLog( methodName + "Python environment path=<" + pythonEnvironmentPath + ">\n" );
                
        // Generate the full command line for the system call
        
        Vector<String> cmdArgs = new Vector<String>(); 
        cmdArgs.addElement( pymolLocation );
        
        // -x Disable external GUI -- causes problems on Mac (maybe other platforms too)
        // Warren recommended -x, but problems
        
        // -i Disable the internal OpenGL GUI (object list, menus, etc.)
        // -q Quiet launch. Suppress splash screen & other chatter.
        // -F command line at bottom of display screen absent
        // -m force Pymol to launch w/ X11; -m causes problems when not using
        // MacBundle (can't find Python sys module
        
         if( osName.compareToIgnoreCase( "Mac" ) == 0 &&
            java.util.regex.Pattern.matches( ".*MacPyMOL$", pymolLocation ) ){
     
           cmdArgs.addElement( "-iFmq" );
        } else {
        	cmdArgs.addElement( "-iFq" );
        }
        
        File workDir = stepParameters.workingDirectory;
        
         // Put later arguments from executable name into command path
        
        for( int ii = 1; ii < initialArgs.size(); ii++) {
            cmdArgs.addElement((String) initialArgs.elementAt(ii));
        }
               
        isimWrapper.appendToLog( methodName + "No. arguments=" + cmdArgs.size() + "\n" );
        
        // Convert to a string array for use by ExternalProcessManager
       
        String[] pymolCommand = new String[cmdArgs.size()];
        pymolCommand = (String[]) cmdArgs.toArray(pymolCommand);
        pymolCommand[2] = workDir.getAbsolutePath() + File.separator + pymolCommand[2];

        // diagnostics

        String message = "\nIssuing Pymol command=<";
        for( int ii = 0; ii < pymolCommand.length; ii++ ){
           message += " " + pymolCommand[ii];
        }
        message += ">\n";
        isimWrapper.appendToLog( message );

        // set the PYMOL_PATH and PYTHONHOME environment variables
        
        Map<String, String>	 environmentMap = new HashMap<String, String>();

        message = "";
        if( osName.compareToIgnoreCase( "Mac" ) == 0 &&
            java.util.regex.Pattern.matches( ".*MacPyMOL$", pymolLocation ) ){
                    
           // not sure why these environment variables are needed
        	
           message += "Setting environment variables CWD and PWD";
           
           environmentMap.put( "CWD",  workDir.getAbsolutePath() );
           environmentMap.put( "PWD",  workDir.getAbsolutePath() );
           
        } else {
        	
        	// Note: if the PYTHONPATH is set then the /System/Framework/.../python2.x
        	// is not searched and the program (Pymol) fails; the ext/lib/python2.x
        	// directory is not supplied w/ the download (it is provided w/ the Windows and
        	// Linux)
        	
        	environmentMap.put( "DISPLAY", ":0.0" );
            environmentMap.put( "PYMOL_PATH",  pymolEnvironmentPath );
            environmentMap.put( "PYTHONHOME",  pythonEnvironmentPath );
            message += "Setting environment variables DISPLAY, PYMOL_PATH, PYTHONHOME";
            
        }
        isimWrapper.appendToLog( message );
        
        // start process, but don't wait for it to complete

        ExternalProcessManager pymolProcess = new ExternalProcessManager(pymolCommand, workDir, environmentMap );
        pymolProcess.setLogDialog( isimWrapper.getLogDialog() );
        pymolProcess.setWaitForCompletion( 0 );
       
        pymolProcess.start();
     
        return;	
    }

    void reportFailure(Exception exc, String msg) {
        exc.printStackTrace();
        stepParameters.task.setStatus(DependentTask.FAILED, msg);
        isimWrapper.appendToLog("Pymol process failed: " + msg + "\n");;
        return;
    }


}
