package ipipan.spejd.processing;

import ipipan.spejd.util.Config;

import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import java.io.File;

public class SpejdManagingProcess extends Thread {

    final static Object lock = new Object();
    public LinkedBlockingQueue<File> FilesToBeProcessed; // list of files waiting to be processed
    public LinkedBlockingQueue<ProcessingRunnable> RnblsInProcessing;
    
    private Config conf;
    
    int ProcessingThreads = 1;
    
          
    public SpejdManagingProcess(LinkedBlockingQueue<File> FilesToBeProcessed, Config conf) {
        this.FilesToBeProcessed = FilesToBeProcessed;
        this.conf = conf;

	// this is the cache for tags parsing
	// it should be saved but at the end,
	// not at the beginning of processing
        // maybe by each thread separately?
	// conf.tagset.saveTagDictionary(conf.logDir);

        if (conf.maxThreads == 0)
            ProcessingThreads = Runtime.getRuntime().availableProcessors();
        else
            ProcessingThreads = conf.maxThreads;
        RnblsInProcessing = new LinkedBlockingQueue<ProcessingRunnable>();
    }
          
    @Override
    public void run() {

        long start = System.currentTimeMillis(); 
          
        ProcessingThreadsFactory ptf = new ProcessingThreadsFactory(lock, conf);
        ExecutorService e = Executors.newCachedThreadPool(ptf);  
          
        // wait in a loop for notification, start new tasks when resources are freed
        int FilesProcessed = 0;
        
        // start processing threads
        processingLoop:
        while (!FilesToBeProcessed.isEmpty() ) {

            // some files wait to be processed
            if (!FilesToBeProcessed.isEmpty()) {
                while ((!FilesToBeProcessed.isEmpty()) && (RnblsInProcessing.size()<ProcessingThreads)) {     

                    File file = FilesToBeProcessed.poll();

                    ProcessingRunnable pr = new ProcessingRunnable(file, RnblsInProcessing);
                    RnblsInProcessing.add(pr);
                    e.execute(pr);
                    FilesProcessed++;
                }
            // file queue empty, wait for disk i/o? 
            } else {
                // no processing threads currently running, sleep here
                // if there are some processing threads, better wait() for them later than here
                try {
                    if (RnblsInProcessing.size()>0) 
                        this.sleep(1);
                } catch (java.lang.InterruptedException ie) { System.err.print(ie); }
                continue processingLoop;
            }

            // wait for a ProcessingRunnable to finish
            while ((!(RnblsInProcessing.size()<(ProcessingThreads-1))) && (RnblsInProcessing.size() > 0)) {
                try {
                    synchronized (lock){
                        if (RnblsInProcessing.size() > 0)
                            lock.wait(10);
                    }
                } catch (InterruptedException ex) { System.err.print(ex); }
                  catch (java.lang.IllegalMonitorStateException imse) { System.err.print(imse); }
            }
        }

        // wait for running threads to finish:
        while (RnblsInProcessing.size()>0) {
            try {
                Thread.sleep(10);
            } catch (InterruptedException ex) { }
        }

        System.out.print(FilesProcessed + " file(s) parsed. ");
        long end = System.currentTimeMillis(); 
        System.out.print(" processing took "+(end-start)+" ms \n");
        


        return;
    }

}