/*
* Lastest Modify: 27 Sep 2011 by Beomsoo Han
*/

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;

/**
 * ModuleExecutor: runs individual feature generating module using Java runtime.
 * 
 * @author yifeng
 * @date Dec 13th, 2009
 * @modified by Beomsoo 
 * 
 */
public class ModuleExecutor {

    // 2011.03.17 - remove WORKING_DIR(./wkdir), save to the same directory of input pdb
	// private static final String WORKING_DIR = "./wkdir/";
	private static String WORKING_DIR = "";

	private static final String RESMF_EXE = "/modules/resmf/resmf";
	private static final String EFFECTS_EXE = "/modules/effects/caleffect"; 
	private static final String ANGLES_EXE = "/modules/angles/get_angles";	
	private static final String ANGLES_REDUCE_DIR = "/modules/angles";

    private static String SHIFTXP_DIR = ShiftXp.SHIFTX2_DIR;

	private static final String REDUCE_FLAG = "1"; // 1 or 0

	private static final boolean DEBUG = ShiftXp.DEBUG;
		
    // update: add pdbdir to support a pdb which is located other directory (2011.03.17)
	public ModuleExecutor(String pdbdir, String pdbfile) {
                WORKING_DIR = pdbdir;
		generate_features(pdbdir, pdbfile);
	}
		
	public static void main(String[] args) {
		if(args.length < 1){
			System.err.println("Usage: java ModuleExecutor <PdbFile>");
			System.exit(-1);
		}
		String pdbdir = args[0];
		String pdbfile = args[1];
		generate_features(pdbdir, pdbfile);
	}

    private static void showMessage(String message) {
        System.out.println("\n***************************************************************");
        System.out.println(message);
        System.out.println("***************************************************************\n\n");

         //  System.exit(1); 
    }

	/**
	 * Generate shiftx prediction features with the given PDB file.
	 * 
	 * @param pdbfile
	 */
	private static void generate_features(String pdbdir, String pdbfile){		
        /* 7 Sep 2011 below three lines with 4th line
           use full input pdb file name including extension
            // String[] filenames = pdbfile.split("\\.");
            // String pdbId = filenames[0];
            // String pdbId = pdbfile.replace(".pdb", "");
        */
        String pdbId = pdbfile;

		String cmd = "";
        int execCode = -1; // 0: OK, others: Error
		
		if(DEBUG) System.out.println("Generating Features for [" + pdbfile + "] ......");

		/* call resmf: main features by residue */
		if(DEBUG) System.out.println("> Processing [Major Features] with " + pdbfile);
        // Update: add pdbdir both input pdbfile and output result, pdbId (2011.03.17)
		// cmd = RESMF_EXE + " -f " + pdbdir +"/"+ pdbfile + " -o " + WORKING_DIR + pdbId + ".resmf";
		cmd = SHIFTXP_DIR + RESMF_EXE + " -f " + pdbdir + pdbfile + " -o " + WORKING_DIR + pdbId + ".resmf" 
                      + " -d " + SHIFTXP_DIR + "/modules/resmf/lib";

		if(DEBUG){ System.out.println("\t"+cmd); }
		execCode = execute_command(cmd); 

        if( execCode != 0 ) {
            showMessage( "[Error in module]\n\t resmf: " + execCode +" for " + pdbfile 
                        +"\n\t # Possible reason is too short residues in pdb files\n");
            System.exit(1);
        }
		
		/* call effects for calculating ring current calculator */
		if(DEBUG) System.out.println("> processing [Effects] with " + pdbfile);
		cmd = SHIFTXP_DIR + EFFECTS_EXE + " 1 " + pdbdir + pdbfile + " " + WORKING_DIR + pdbfile + ".dummy";

		if(DEBUG){ System.out.println("\t"+cmd); }
		execCode = execute_command(cmd); 
		
        if( execCode != 0 ) {
            showMessage( "[Error in module]\n\t effect: " + execCode);
            System.exit(1);
        }

		/* call angle calculator : output must be redirected to file using PrintStream */
		if(DEBUG) System.out.println("> Processing [Angle] with " + pdbfile);
		// cmd = ANGLES_EXE + " " + ANGLES_REDUCE_DIR + " " + pdbfile ;
		cmd = SHIFTXP_DIR + ANGLES_EXE + " " + SHIFTXP_DIR + ANGLES_REDUCE_DIR + " " + pdbdir + pdbfile + " "+ REDUCE_FLAG;
		String outpath = WORKING_DIR + pdbId + ".angles";

		if(DEBUG){ System.out.println("\t"+cmd); }
        // switched because of memory error and use the changed angle program 
        // 30 SEP 2011 by Beomsoo Han 
		// execCode = execute_command(cmd, outpath); 
		execCode = execute_command(cmd); 

        if( execCode != 0 ) {
            showMessage( "[Error in module]\n\t angles: " + execCode );
            System.exit(1);
        }

		if(DEBUG && execCode ==0) System.out.println("Features are generated\n");
        else if( execCode != 0) System.out.println("\nError! while generating features\n"); 
	}
	
	/**
	 * Execute a given command in Java runtime; 
	 * output from program are saved in the specified output file.
	 * @param cmd: the command to be executed
	 * @return
	 * @throws  
	 */
	private static int execute_command(String cmd) {

		int exitValue = -1;
		try{

			Process process = Runtime.getRuntime().exec(cmd);
			// process = Runtime.getRuntime().exec(cmd);
		    process.waitFor();
			exitValue = process.exitValue();
		}catch(IOException ex){
			ex.printStackTrace();
            System.exit(1);
		}catch(InterruptedException ex){
			ex.printStackTrace();
            System.exit(1);
        }

		if(DEBUG){ System.out.println("\tExit Value: " + exitValue); }
		return exitValue;
	}

	/**
	 * Execute a given command in Java runtime.
	 * Program outputs to stdout so we use PrintStream to redirect it to a file.
	 * @param cmd: the command to be executed
	 * @param outPath: path of the output file.
	 * @return
	 * @throws  
	 */
	private static int execute_command(String cmd, String outPath) {
		int exitValue = -1;
		try{
			Process process = Runtime.getRuntime().exec(cmd);
			// process = Runtime.getRuntime().exec(cmd);
			InputStream in = process.getInputStream();
			PrintStream ps = new PrintStream(new FileOutputStream(new File(outPath)));
			int c;
			while((c = in.read()) != -1){
				ps.print((char) c);
			}
			in.close();
			ps.close();
			exitValue = process.exitValue();
		}catch(IOException ex){
			ex.printStackTrace();
            System.exit(1);
		}
		if(DEBUG){ System.out.println("\tExit Value: " + exitValue); }
		return exitValue;
	}

}
