package org.jboss.windup.config;

import java.util.ArrayList;
import java.util.List;

import org.jboss.windup.config.operation.Iteration;
import org.jboss.windup.config.operation.iteration.AbstractIterationOperation;
import org.ocpsoft.rewrite.config.CompositeOperation;
import org.ocpsoft.rewrite.config.Condition;
import org.ocpsoft.rewrite.config.Operation;
import org.ocpsoft.rewrite.spi.ConfigurationRuleBuilderInterceptor;

public class SimpleIterationConfigurationRuleBuilderInterceptor implements ConfigurationRuleBuilderInterceptor {

    @Override
    public Operation perform(Operation operation) {
        return detectImplicitIteration(operation);
    }

    @Override
    public List<Operation> perform(List<Operation> list) {
        return detectImplicitIteration(list);
    }

    @Override
    public Operation otherwise(Operation operation) {
        return perform(operation);
    }

    @Override
    public List<Operation> otherwise(List<Operation> list) {
        return perform(list);
    }

    private List<Operation> detectImplicitIteration(List<Operation> list) {
        List<Operation> result = new ArrayList<>();

        if (list != null) {
            boolean requiresIteration = false;
            for (Operation operation : list) {
                if (requiresIteration(operation)) {
                    requiresIteration = true;
                    break;
                }
            }

            if (requiresIteration) {
                result.add(Iteration.over().perform(list.toArray(new Operation[list.size()])).endIteration());
            } else {
                result = list;
            }
        }

        return result;
    }

    private Operation detectImplicitIteration(Operation operation) {
        if (requiresIteration(operation)) {
            return Iteration.over().perform(operation).endIteration();
        }

        return operation;
    }

    private boolean requiresIteration(Operation operation) {
        if (operation instanceof Iteration) {
            return false;
        }

        if (operation instanceof AbstractIterationOperation)
            return true;

        if (operation instanceof CompositeOperation) {
            List<Operation> operations = ((CompositeOperation) operation).getOperations();
            for (Operation op : operations) {
                if (op instanceof AbstractIterationOperation)
                    return true;
                else if (!(op instanceof Iteration) && requiresIteration(op))
                    return true;
            }
        }

        return false;
    }

    /*
     * Things we don't care about for this interceptor
     */

    @Override
    public Condition when(Condition condition) {
        return condition;
    }

    @Override
    public List<Condition> when(List<Condition> list) {
        return list;
    }

    @Override
    public int withPriority(int priority) {
        return priority;
    }

    @Override
    public String withId(String id) {
        return id;
    }

    @Override
    public int priority() {
        return 0;
    }
}
