package roart.content;

import java.io.File;
import java.util.Date;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import roart.model.Index;
import roart.queue.Queues;
import roart.queue.TikaQueueElement;
import roart.util.ExecCommand;

public class OtherHandler {
	
	private static Log log = LogFactory.getLog("OtherHandler");
	
    public static void doOther()  {
    	TikaQueueElement el = Queues.otherQueue.poll();
    	if (el == null) {
    		log.error("empty queue");
    	    return;
    	}
    	// vulnerable spot
    	Queues.incOthers();
    	long now = new Date().getTime();
    	
    	String dbfilename = el.dbfilename;
    	String filename = el.filename;
    	String md5 = el.md5;
    	Index index = el.index;
    	List<String> retlist = el.retlist;

	String output = null;
	boolean retry = false;
	String lowercase = filename.toLowerCase();
	File temp = null;
	String tmp = null;
    try {
	temp = File.createTempFile("other", ".txt");
    tmp = temp.getAbsolutePath();
    } catch (Exception e) {
     log.error("Exception", e);
    }
	// epub 2nd try
	if (lowercase.endsWith(".mobi") || lowercase.endsWith(".pdb") || lowercase.endsWith(".epub") || lowercase.endsWith(".lit") || lowercase.endsWith(".djvu") || lowercase.endsWith(".djv") || lowercase.endsWith(".dj") || lowercase.endsWith(".chm")) {
	    File file = new File(filename);
	    String dirname = file.getParent();
	    File dir = new File(dirname);
	    boolean w = dir.canWrite();
	    if (!w) {
		dir.setWritable(true);
	    }
	    String[] arg = { filename, tmp };
	    output = executeTimeout("/usr/bin/ebook-convert", arg);
	    if (!w) {
		dir.setWritable(false);
	    }
	    retry = true;
	}
	// djvu 2nd try in case djvu not ebook-convert supported
	if (output != null && output.contains("ValueError: No plugin to handle input format: dj")) {
	    String[] arg = { filename, tmp };
	    output = executeTimeout("/usr/bin/djvutxt", arg);
	    retry = true;
	}
	// pdf 2nd try
	if (lowercase.endsWith(".pdf")) {
	    String[] arg = { filename, tmp };
	    output = executeTimeout("/usr/bin/pdftotext", arg);
	    retry = true;
	}
	File txt = temp;
	if (retry && txt.exists()) {
	    TikaQueueElement e = new TikaQueueElement(filename, tmp, md5, index, retlist);
	    Queues.tikaQueue.add(e);
	    //size = doTika(filename, tmp, md5, index, retlist);
	}
	if (false && txt.exists()) {
		 txt.delete();
	}
	log.info("timerStop " + (new Date().getTime() - now));
	Queues.decOthers();
	
    }
    
    private static java.util.Queue<Object[]> execQueue = new ConcurrentLinkedQueue<Object[]>();

    private static String execute(String filename, String[] arg) {
	String res = null;

	ExecCommand ec = new ExecCommand();
	ec.execute(filename, arg);

	res = ec.getOutput() + ec.getError();
	log.info("output " + res);
	return res;
    }
    
    public static Object executeQueue() {
    	Object [] objs = execQueue.poll();
    	String filename = (String) objs[0];
    	String [] arg = (String []) objs[1];
    	return execute(filename, arg);
    }
    
    public static String executeTimeout(String filename, String [] arg) {
    	Object [] objs = new Object[2];
    	objs[0] = filename;
    	objs[1] = arg;
    	execQueue.add(objs);
        Callable<Object> callable = new Callable<Object>() {
            public Object call() throws Exception {
                return executeQueue();
            }
        };
        ExecutorService executorService = Executors.newCachedThreadPool();

        Future<Object> task = executorService.submit(callable);
        Object result = null;
        try {
            // ok, wait for 600 seconds max
            result = task.get(600, TimeUnit.SECONDS);
            log.info("Finished with result: " + result);
        } catch (ExecutionException e) {
            throw new RuntimeException(e);
        } catch (TimeoutException e) {
            log.error("timeout...", e);
        } catch (InterruptedException e) {
            log.error("interrupted", e);
        }
        executorService.shutdown();  
        return (String) result;
    }

}
@@ -1995,24 +1995,33 @@
 onvert%22, arg
+, retlist
 );%0A%09    if (
@@ -2316,32 +2316,41 @@
 in/djvutxt%22, arg
+, retlist
 );%0A%09    retry = 
@@ -2502,16 +2502,25 @@
 xt%22, arg
+, retlist
 );%0A%09    
@@ -2559,36 +2559,261 @@
 p;%0A%09
-if (retry && txt.exists()) %7B
+long time = new Date().getTime() - now;%0A%09log.info(%22timerStop %22 + dbfilename + %22 %22 + time);%0A%09if (retry && txt.exists()) %7B%0A%09%09log.info(%22handling filename %22 + dbfilename + %22 : %22 + time);%0A%09%09retlist.add(%22other handling filename %22 + dbfilename + %22 : %22 + time);
 %0A%09  
@@ -2987,114 +2987,124 @@
 ;%0A%09%7D
-%0A%09if (false && txt.exists()) %7B%0A%09%09 txt.delete();%0A%09%7D%0A%09log.info(%22timerStop %22 + (new Date().getTime() - now));
+ else %7B%0A%09%09log.info(%22handled not %22 + dbfilename + %22 : %22 + time);%0A%09%7D%0A%09if (false && txt.exists()) %7B%0A%09%09 txt.delete();%0A%09%7D
 %0A%09Qu
@@ -3754,24 +3754,46 @@
 tring %5B%5D arg
+, List%3CString%3E retlist
 ) %7B%0A    %09Obj
@@ -4565,15 +4565,118 @@
 eout
-...%22, e
+ running %22 + filename + %22 %22 + arg%5B0%5D, e);%0A            retlist.add(%22timeout running %22 + filename + %22 %22 + arg%5B0%5D
 );%0A 

logging. web retlist