/*
 * Copyright 2012 JBoss Inc
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.optaplanner.core.impl.heuristic.selector.move.composite;

import java.util.List;

import org.optaplanner.core.api.domain.valuerange.ValueRange;
import org.optaplanner.core.impl.heuristic.selector.move.AbstractMoveSelector;
import org.optaplanner.core.impl.heuristic.selector.move.MoveSelector;

/**
 * Abstract superclass for every composite {@link MoveSelector}.
 * @see MoveSelector
 */
public abstract class CompositeMoveSelector extends AbstractMoveSelector {

    protected final List<MoveSelector> childMoveSelectorList;
    protected final boolean randomSelection;

    protected CompositeMoveSelector(List<MoveSelector> childMoveSelectorList, boolean randomSelection) {
        this.childMoveSelectorList = childMoveSelectorList;
        this.randomSelection = randomSelection;
        for (MoveSelector childMoveSelector : childMoveSelectorList) {
            phaseLifecycleSupport.addEventListener(childMoveSelector);
        }
        if (!randomSelection) {
            // Only the last childMoveSelector can be neverEnding
            if (!childMoveSelectorList.isEmpty()) {
                for (MoveSelector childMoveSelector
                        : childMoveSelectorList.subList(0, childMoveSelectorList.size() - 1)) {
                    if (childMoveSelector.isNeverEnding()) {
                        throw new IllegalStateException("The selector (" + this
                                + ")'s non-last childMoveSelector (" + childMoveSelector
                                + ") has neverEnding (" + childMoveSelector.isNeverEnding()
                                + ") with randomSelection (" + randomSelection + ")."
                                + (childMoveSelector.isCountable() ? ""
                                : "\nThe selector is not countable, check the "
                                + ValueRange.class.getSimpleName() + "s involved."));
                    }
                }
            }
        }
    }

    public List<MoveSelector> getChildMoveSelectorList() {
        return childMoveSelectorList;
    }

    // ************************************************************************
    // Worker methods
    // ************************************************************************

    public boolean isCountable() {
        for (MoveSelector moveSelector : childMoveSelectorList) {
            if (!moveSelector.isCountable()) {
                return false;
            }
        }
        return true;
    }

    @Override
    public String toString() {
        return getClass().getSimpleName() + "(" + childMoveSelectorList + ")";
    }

}

@@ -658,16 +658,45 @@
 osite;%0A%0A
+import java.util.Collection;%0A
 import j
@@ -761,16 +761,25 @@
 uerange.
+Countable
 ValueRan
@@ -782,16 +782,148 @@
 eRange;%0A
+import org.optaplanner.core.api.domain.valuerange.ValueRange;%0Aimport org.optaplanner.core.api.domain.valuerange.ValueRangeProvider;%0A
 import o
@@ -2647,16 +2647,384 @@
 nvolved.
+%5Cn%22%0A                                + %22Verify that a %22 + ValueRangeProvider.class.getSimpleName()%0A                                + %22 does not return %22 + ValueRange.class.getSimpleName()%0A                                + %22 when it can return %22 + CountableValueRange.class.getSimpleName()%0A                                + %22 or %22 + Collection.class.getSimpleName() + %22.
 %22));%0A   

Improve error message when ValueRange instead of CountableValueRange is used.