package com.lanyuanxiaoyao.service.scheduler.quartz.distribute.strategy;

import org.eclipse.collections.api.factory.Lists;
import org.eclipse.collections.api.list.ImmutableList;

/**
 * 判断集群是否有可用资源的策略
 *
 * @author ZhangJiacheng
 * @date 2023-05-31
 */
public interface AvailableStrategy {
    static AvailableStrategy and(AvailableStrategy... strategies) {
        return new AndAvailableStrategy(strategies);
    }

    static AvailableStrategy or(AvailableStrategy... strategies) {
        return new OrAvailableStrategy(strategies);
    }

    static AvailableStrategy whether(AvailableStrategy condition, AvailableStrategy trueOption, AvailableStrategy falseOption) {
        return new WhetherAvailableStrategy(condition, trueOption, falseOption);
    }

    boolean available();

    abstract class BaseAvailableStrategy implements AvailableStrategy {
        protected final ImmutableList<AvailableStrategy> strategies;

        public BaseAvailableStrategy(AvailableStrategy... strategies) {
            this.strategies = Lists.immutable.of(strategies);
        }
    }

    final class AndAvailableStrategy extends BaseAvailableStrategy {
        public AndAvailableStrategy(AvailableStrategy... strategies) {
            super(strategies);
        }

        @Override
        public boolean available() {
            return strategies.allSatisfy(AvailableStrategy::available);
        }
    }

    final class OrAvailableStrategy extends BaseAvailableStrategy {
        public OrAvailableStrategy(AvailableStrategy... strategies) {
            super(strategies);
        }

        @Override
        public boolean available() {
            return strategies.anySatisfy(AvailableStrategy::available);
        }
    }

    final class WhetherAvailableStrategy implements AvailableStrategy {
        private final AvailableStrategy condition;
        private final AvailableStrategy trueOption;
        private final AvailableStrategy falseOption;

        public WhetherAvailableStrategy(AvailableStrategy condition, AvailableStrategy trueOption, AvailableStrategy falseOption) {
            this.condition = condition;
            this.trueOption = trueOption;
            this.falseOption = falseOption;
        }

        @Override
        public boolean available() {
            return condition.available() ? trueOption.available() : falseOption.available();
        }
    }
}
