package com.github.sommeri.less4j.core.compiler.stages;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import com.github.sommeri.less4j.core.ast.ASTCssNode;
import com.github.sommeri.less4j.core.ast.MixinReference;
import com.github.sommeri.less4j.core.compiler.expressions.GuardValue;
import com.github.sommeri.less4j.core.problems.BugHappened;
import com.github.sommeri.less4j.core.problems.ProblemsHandler;
import com.github.sommeri.less4j.utils.ArraysUtils;
public class DefaultGuardHelper {
private final ProblemsHandler problemsHandler;
public DefaultGuardHelper(ProblemsHandler problemsHandler) {
this.problemsHandler = problemsHandler;
}
public List<BodyCompilationData> chooseMixinsToBeUsed(List<BodyCompilationData> compiledMixins, final MixinReference reference) {
// count how many mixins of each kind we encountered
int normalMixinsCnt = ArraysUtils.count(compiledMixins, GuardValue.USE.filter());
int ifNotCnt = ArraysUtils.count(compiledMixins, GuardValue.USE_IF_NOT_DEFAULT.filter());
int ifDefaultCnt = ArraysUtils.count(compiledMixins, GuardValue.USE_IF_DEFAULT.filter());
int doNotUse = ArraysUtils.count(compiledMixins, GuardValue.DO_NOT_USE.filter());
//sanity check - could be removed - keeping only for debugging purposes
if (normalMixinsCnt+ifNotCnt+ifDefaultCnt+doNotUse!=compiledMixins.size())
throw new BugHappened("Unexpected mixin type in compiled mixins list.", reference);
// We know now that default() value is false. We do not care whether there was some potentional ambiguity or not and return anything that is not default.
if (normalMixinsCnt > 0) {
return keepOnly(compiledMixins, GuardValue.USE, GuardValue.USE_IF_NOT_DEFAULT);
}
//there are multiple mixins using default() function and nothing else - that is ambiguous (period).
if (ifDefaultCnt+ifNotCnt > 1) {
List<BodyCompilationData> errorSet = keepOnly(compiledMixins, GuardValue.USE_IF_DEFAULT,GuardValue.USE_IF_NOT_DEFAULT);
problemsHandler.ambiguousDefaultSet(reference, extractOriginalMixins(errorSet));
//no mixins are going to be used
return Collections.emptyList();
}
//now we know that default function returns true
return keepOnly(compiledMixins, GuardValue.USE_IF_DEFAULT);
}
/**
* Removes all comiled mixins from compiledMixins list with wrong use of default function.
* Warning: Modifies the compiledMixins list.
* @param compiledMixins - list of compiled mixins - will be modified.
* @param kind - types of mixins that are going to stay.
* @return compiledMixins - for convenience
*/
private List<BodyCompilationData> keepOnly(List<BodyCompilationData> compiledMixins, GuardValue... kind) {
Set<GuardValue> expectedUses = ArraysUtils.asSet(kind);
Iterator<BodyCompilationData> iterator = compiledMixins.iterator();
while (iterator.hasNext()) {
BodyCompilationData compiled = iterator.next();
if (!expectedUses.contains(compiled.getGuardValue())) {
iterator.remove();
}
}
return compiledMixins;
}
private List<ASTCssNode> extractOriginalMixins(List<BodyCompilationData> compiledMixins) {
List<ASTCssNode> result = new ArrayList<ASTCssNode>();
for (BodyCompilationData compiled : compiledMixins) {
result.add((ASTCssNode)compiled.getCompiledBodyOwner());
}
return result;
}
}