package com.ragnarok.jparseutil.filescanner;

import com.ragnarok.jparseutil.dataobject.CodeInfo;
import com.ragnarok.jparseutil.util.Log;

import java.io.FileNotFoundException;
import java.util.List;
import java.util.concurrent.*;

/**
 * Created by ragnarok on 15/8/23.
 * this JavaFileScanner parallel scan all files with configurable multi thread support
 */
public class MultiThreadJavaFileScanner extends JavaFileScanner {
    
    public static final String TAG = "JParserUtil.MultiThreadJavaFileScanner";
    
    private int threadNumber;
    
    private ThreadPoolExecutor executor;
    
    private LinkedBlockingQueue<Runnable> workerQueue;
    
    public MultiThreadJavaFileScanner(String dir, int threadNumber) {
        super(dir);
        this.threadNumber = threadNumber;
        initThreadPool();
    }
    
    private void initThreadPool() {
        workerQueue = new LinkedBlockingQueue<>();
        executor = new ThreadPoolExecutor(threadNumber, threadNumber, 2L, TimeUnit.SECONDS, workerQueue);
    }
    
    private class ScanSubSetFileRunnable implements Runnable {

        private List<String> subSetFileList;
        private int threadNo;
        
        public ScanSubSetFileRunnable(List<String> subSetFileList, int threadNo) {
            this.subSetFileList = subSetFileList;
            this.threadNo = threadNo;
        }
        
        @Override
        public void run() {
            for (String file : subSetFileList) {
                parseJavaSource(file);
            }
            Log.i(TAG, "thread %d parsing finished", threadNo);
        }
    }

    @Override
    public CodeInfo scanAllJavaSources() throws FileNotFoundException {
        if (executor == null || executor.isShutdown()) {
            initThreadPool();
        }
        
        result = new CodeInfo();
        initJavaSourcePaths();
        Log.d(TAG, "filelist size: %d", allJavaSourcePaths.size());
        
        int sourceSetSize = allJavaSourcePaths.size();
        int pieceSize = sourceSetSize / threadNumber;
                
        Log.i(TAG, "start scan, threadNumber: %d, sourceSetSize: %d, pieceSize: %d", threadNumber, sourceSetSize, pieceSize);
        
        int currentStartIndex = 0;

        Future[] futureList = new Future[threadNumber];
        
        for (int i = 0; i < threadNumber; i++) {
            int startIndex = currentStartIndex > allJavaSourcePaths.size() ? allJavaSourcePaths.size() - 1 : currentStartIndex;
            int endIndex = startIndex + pieceSize > allJavaSourcePaths.size() ? allJavaSourcePaths.size() - 1 : startIndex + pieceSize;
            
            if (i == threadNumber -1 && endIndex < allJavaSourcePaths.size()) {
                endIndex = allJavaSourcePaths.size();
            }
            
            Log.d(TAG, "startIndex: %d, endIndex: %d", startIndex, endIndex);
            
            futureList[i] = executor.submit(new ScanSubSetFileRunnable(allJavaSourcePaths.subList(startIndex, endIndex), i));
            
            currentStartIndex = endIndex;
        }
        
        
        for (Future future : futureList) {
            try {
                future.get();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        }
        
        executor.shutdown();
        
        return result;
    }
}

@@ -74,22 +74,128 @@
 til.
-dataobject.Cod
+SourceInfoExtracter;%0Aimport com.ragnarok.jparseutil.dataobject.CodeInfo;%0Aimport com.ragnarok.jparseutil.dataobject.Sourc
 eInf
@@ -1271,32 +1271,81 @@
 eadNo;%0A        %0A
+        private CodeInfo subTaskResult;%0A        %0A
         public S
@@ -1491,32 +1491,76 @@
 dNo = threadNo;%0A
+            subTaskResult = new CodeInfo();%0A
         %7D%0A      
@@ -1677,124 +1677,450 @@
     
-parseJavaSource(file);%0A            %7D%0A            Log.i(TAG, %22thread %25d parsing finished%22, threadNo);%0A        %7D%0A    %7D
+SourceInfoExtracter extracter = new SourceInfoExtracter(file);%0A                SourceInfo sourceInfo = extracter.extract();%0A                if (sourceInfo != null) %7B%0A                    subTaskResult.addSource(sourceInfo);%0A                %7D%0A            %7D%0A            Log.i(TAG, %22thread %25d parsing finished%22, threadNo);%0A        %7D%0A        %0A        public CodeInfo getSubTaskResult() %7B%0A            return subTaskResult;%0A        %7D%0A    %7D%0A    %0A    
 %0A%0A  
@@ -2803,16 +2803,106 @@
 umber%5D;%0A
+        ScanSubSetFileRunnable%5B%5D runnableList = new ScanSubSetFileRunnable%5BthreadNumber%5D;%0A
         
@@ -3467,28 +3467,16 @@
 Index);%0A
-            
 %0A       
@@ -3480,21 +3480,23 @@
         
-futur
+runnabl
 eList%5Bi%5D
@@ -3502,24 +3502,8 @@
 %5D = 
-executor.submit(
 new 
@@ -3577,16 +3577,77 @@
 dex), i)
+;%0A            futureList%5Bi%5D = executor.submit(runnableList%5Bi%5D
 );%0A     
@@ -4006,32 +4006,175 @@
      %7D%0A        %0A
+        for (ScanSubSetFileRunnable runnable : runnableList) %7B%0A            result.addCodeInfo(runnable.getSubTaskResult());%0A        %7D%0A        %0A
         executor

split different sub task