/*
 * Copyright 2018 Scytl Secure Electronic Voting SA
 *
 * All rights reserved
 *
 * See our extended copyright notice in *file 'Copyright.txt' which is part of this source code package
 */
package com.scytl.ov.mixing.commons.concurrent;

import static java.util.Collections.singletonList;

import java.util.Deque;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.RecursiveAction;

import com.scytl.ov.mixing.commons.tools.LoopTools.Range;
import com.scytl.ov.mixing.commons.concurrent.ParallelProcessAction;

/**
 * This class is in charge of: split the tasks one by Range object, execute the base case (passed on the constructor as
 * a {@code ParallelProcessTask} class) and wait until all executions are finished
 */
@SuppressWarnings("serial")
public final class LoopParallelizerAction extends RecursiveAction {
    private final transient ParallelProcessAction process;

    private final transient List<Range> ranges;

    /**
     * Constructor.
     * 
     * @param process
     */
    public LoopParallelizerAction(final ParallelProcessAction process, final List<Range> ranges) {
        this.process = process;
        this.ranges = ranges;
    }
    
    @Override
    protected void compute() {
        if (ranges.size() == 1) {
            process.run(ranges.get(0));
            return;
        }
        
        Deque<LoopParallelizerAction> stack = new LinkedList<>();
        for (Range range : ranges.subList(1, ranges.size())) {
            LoopParallelizerAction action = 
                    new LoopParallelizerAction(process, singletonList(range));
            action.fork();
            stack.push(action);
        }

        process.run(ranges.get(0));
        
        while(!stack.isEmpty()) {
            LoopParallelizerAction action = stack.pop();
            if (action.tryUnfork()) {
                action.compute();
            } else {
                action.join();
            }
        }
    }
}
