/* Copyright (c) 2005 Stanford University and Christopher Bruns
 * 
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including 
 * without limitation the rights to use, copy, modify, merge, publish, 
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject
 * to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included 
 * in all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

/*
 * Created on Sep 20, 2005
 * Original author: Christopher Bruns
 */
package org.simtk.isimsu;

import java.io.*;
import java.util.*;

/**
 *  
  * @author Christopher Bruns
  * 
  * Manages the conversion of a PDB format structure file to PQR format, needed by APBS and ISIM
  */
public class PDBToPQRThread extends JarDefinedExecutableThread {
    ISIMStepParameters stepParams;
    // private static boolean executableIsUnpacked = false;
    File pdbFile;
    APBSParameters apbsParams;
    ISIMWrapper parentFrame;
    
    // Constructor
    PDBToPQRThread(ISIMStepParameters s, APBSParameters a, File f, ISIMWrapper parentFrame) {
        stepParams = s;
        pdbFile = f;
        apbsParams = a;
        this.parentFrame = parentFrame;
    }
    
    public void run() {
        parentFrame.appendToLog("Running pdb2pqr...\n");
        
        if ( (pdbFile != null) && (pdbFile.exists()) ) {
            
            // Make sure another version of this task is not already running
            ISIMTask task = stepParams.task;
            // This task IS already running because format conversion is not the first step of the task
            // So we do not want to quit just because the task is running
            // if (task.isRunning()) return;        
            
            // Get the platform-specific command name from a file in the jar file
            Vector initialArgs = new Vector();
            try {
                initialArgs = unpackExecutable("pdb2pqr", "pdb2pqr_executable_name", stepParams.programDirectory);
            } catch (IOException exc) {
                reportFailure(exc);
            }
                        
            // Convert pdb file to pqr file in working area
            
            String exeFileName = (String) initialArgs.elementAt(0);
            
            // Convert file name to absolute path
            // This fails if exeFileName is "python pdb2pqr.py"
            File exeFile = new File( stepParams.programDirectory, exeFileName);
            if (exeFile.exists()) 
                exeFileName = exeFile.getAbsolutePath();
            else {
                // In this case we just hope that the executable file is on the current executable path...
                // reportFailure(new Exception("Executable file does not exist"));
                // don't return -- the normal python case is here on Mac and Linux
            }
            
            // Construct the conversion command line
            // String pdbFileName = pdbFile.getAbsolutePath(); // danger - might contain spaces
            String pdbFileName = pdbFile.getName();
            String pqrFileName = pdbFileName.replaceAll("\\.(pdb|PDB|ent|ENT|brk|BRK)[0-9]*$", "") + ".pqr";
            // System.out.println("Convert " + pdbFileName + " to " + pqrFileName);
            
            String forceField = "charmm";
            
            parentFrame.appendToLog("Using \'"+forceField+"\' forcefield for pdb2pqr\n");
            
            Vector<String> cmdArgs = new Vector<String>();
            cmdArgs.addElement(exeFileName); // The command itself
            // Add other loaded arguments from file
            // Put later arguments from executable name into command path
            for (int i = 1; i < initialArgs.size(); i ++) {
                cmdArgs.addElement((String) initialArgs.elementAt(i));
            }
            cmdArgs.addElement("--ff=" + forceField); // required argument
            cmdArgs.addElement(pdbFileName);
            cmdArgs.addElement(pqrFileName);
            String[] pdb2pqrCommand = new String[cmdArgs.size()];
            pdb2pqrCommand = (String[]) cmdArgs.toArray(pdb2pqrCommand);
            
            // Actually run it
            ExternalProcessManager programThread = new ExternalProcessManager(pdb2pqrCommand, stepParams.workingDirectory);
            programThread.start(); // Run the program

            try { // wait for it to finish
                programThread.join();
                File pqrFile = new File(stepParams.workingDirectory, pqrFileName);

                parentFrame.appendToLog("\n\nPDB2PQR Standard Output:\n\n");
                parentFrame.appendToLog(programThread.getStdOut());
                parentFrame.appendToLog("\n\nPDB2PQR Standard Error:\n\n");
                parentFrame.appendToLog(programThread.getStdErr());
                
                if (programThread.exception != null) {
                    // FAILURE of process
                    reportFailure(programThread.exception);
                }                
                else if (pqrFile.exists()) {
                    // SUCCESS
                    setPqrFile(pqrFile);                   
                }
                else {
                    // FAILURE - no file created
                    reportFailure(new Exception("No output file created"));
                }                
                return;
            }
            catch (InterruptedException exc) {
                reportFailure(exc);
                return;
            }
        }
        
        else {
            reportFailure(new Exception("PDB file cannot be opened"));
        }
    }

    void reportFailure(Exception exc) {
        exc.printStackTrace();
        setFailed();
        return;        
    }
    
    public void setPqrFile(File pqrFile) {
        parentFrame.setPqrFile(pqrFile);
        setSuccessful();
    }
    
    public void setFailed(String msg) {
        super.setFailed();
        stepParams.task.setStatus(DependentTask.FAILED, msg);
    }
}
