/*
 * $Id: ProcessKiller.java,v 1.3 2004/11/10 15:02:46 koppy Exp $
 *
 * Copyright (c) Siemens AG 2008 
 *           (c) Universität Paderborn 2008 
 * Licensed under EUPL 1.1. 
 * 
 * Created on 24.08.2004
 *
 * $Log: ProcessKiller.java,v $
 * Revision 1.3  2004/11/10 15:02:46  koppy
 * Projektweite Überarbeitung von Error-Logs, Stacktraces,..
 *
 * Revision 1.2  2004/08/31 14:15:49  lawern
 * ProcessKiller eingebaut
 *
 * Revision 1.1  2004/08/26 14:38:33  koppy
 * Klasse zum Abschießen von Prozessen, die eine gegebene Datei
 * nach gegebenem Timeout immer noch sperren.
 *
 */
package vkc.misc;

import vkc.converter.DocConverter;



/**
 * This class gives a possibility to
 * kill a process that still locks a file
 * after the given timeout.
 * 
 * @author Andreas Koop
 */
public class ProcessKiller extends Thread {

    private String binDir = null;
    private String filename = null;
    private int timeoutMinutes = 0;
    
    /**
     * 
     * @param filename
     * @param timeoutMinutes
     */
    public ProcessKiller( String filename, int timeoutMinutes){
        this.filename = filename;
        this.timeoutMinutes = timeoutMinutes;
        this.binDir = DocConverter.getBasePath();
    }
    
    
    /**
     * 
     * @param binDir
     * @param filename
     * @param timeoutMinutes
     */
    public ProcessKiller( String binDir, String filename, int timeoutMinutes){
        this(filename,timeoutMinutes);
        this.binDir = binDir;
    }
    
    
    public void run() {
        
        try {
            Thread.sleep( timeoutMinutes*60*1000 );
        } catch (InterruptedException e) {
            return;
        }
        killProcessByFileHandle();
        
    }

    /**
     * Kills all processes (except java)
     * that are locking the given file.
     */
    private void killProcessByFileHandle() {
        
        VKCProcess handleProcess = new VKCProcess(
                new String[]{ binDir + "/WhoUses.exe", filename}, null, null);
        
        int exitCode = handleProcess.execute();
        if(exitCode == 0){
            
            String [] ss = handleProcess.getStandardOutput().split("\n");
            for (int i = 2; i < ss.length; i++) {
                WhoUsesEntry e = new WhoUsesEntry(ss[i]);
                if( !e.getFileName().toLowerCase().startsWith( "java"))
                    e.killProcess();
            }
            
            
        }
      
    }
    
    
    
    /**
     * For testing purposes
     * @param args
     */
    public static void main ( String [] args ){
       
        VKCLogManager.init( "c:/temp/test_", ".log" );
        VKCLogManager.setEnableLogging(true);
        VKCLogManager.setLogToConsole(true);
        
        ProcessKiller killer = new ProcessKiller( 
                					"D:/work/eclipse3/VKC3/bin/win32",
                					"nachweis.xls", 1);
        
        killer.killProcessByFileHandle();
        
    }
    
    /**
     * This class represents a parser
     * for a line of the WhoUses.exe result string.
     * @author Andreas Koop
     */
    private class WhoUsesEntry{
        private String line = null;
        public WhoUsesEntry( String line ){
            this.line = line;
        }
        
        /**
         * Kills the associated process
         * @return true, if succeeded. false otherwise.
         */
        public boolean killProcess(){
            VKCProcess killProcess = new VKCProcess(
                    new String[]{ "taskkill.exe", "/PID", ""+getPID() ,"/F"}, null, null);
            
            int exitCode = killProcess.execute();
            if(exitCode == 0){
                return true;
            }
            
            return false;
        }
        
        public int getPID(){
            return hex2Int(line.substring(0,6));
        }
        
        public String getProcessName(){
            return line.substring(8,30).trim();
        }
        
        public String getFileName(){
            return line.substring(30).trim();
        }
        
        public String toString(){
            return "PID:  "+ this.getPID() 
            		+  "\nName: "+ this.getProcessName()
            		+  "\nFile: "+ this.getFileName();
        }
        
        private int hex2Int(String s){
            String HEX_DIGITS = "0123456789abcdef";
            int value = 0;

            s = s.toLowerCase();
            for (int i = s.length() - 1, j = 0; i >= 0; i--, j++){
                char ch = s.charAt(i);
                if(ch == 'x')
                    break;
                value += HEX_DIGITS.indexOf(ch)*((int) Math.pow(16, j));
            }
                
                    

            return(value);
        }
    }
}
