package com.apobates.forum.strategy.exposure.config;

import com.apobates.forum.member.entity.Member;
import com.apobates.forum.strategy.StrategyMode;
import com.apobates.forum.strategy.exception.StrategyException;
import com.apobates.forum.utils.lang.TriPredicate;
import java.util.Optional;
import java.util.function.BiPredicate;
import java.util.function.Predicate;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.ImmutableTriple;

/**
 * 配置文件策略执行链,并封装执行结果
 * 
 * @param <T> 实体类型参数
 * @param <C> 实体配置文件类型参数
 * @author xiaofanku
 * @since 20200828
 */
public final class ConfigStrategyChain<T, C> {
    private final boolean result;
    private final StrategyException exception;
    
    private ConfigStrategyChain(boolean result, StrategyException exception) {
        this.result = result;
        this.exception = exception;
    }
    
    public static <T,C> ConfigStrategyChain<T,C> start() {
        return new ConfigStrategyChain<>(true, null);
    }
    /**
     * 
     * @param configFunction 配置文件谓词函数
     * @param config 实体配置文件
     * @return 
     */
    public ConfigStrategyChain<T,C> config(Predicate<C> configFunction, C config){
        if(!isContinue()){
            return this;
        }
        //
        try{
            if(configFunction.test(config)){
                return new ConfigStrategyChain<>(true, null);
            }
        }catch(StrategyException e){
            return new ConfigStrategyChain<>(false, e);
        }
        return new ConfigStrategyChain<>(false, new StrategyException("实体配置文件检测失败"));
    }
    /**
     * 
     * @param entityFunction 实体谓词函数
     * @param argument 实体谓词函数参数
     * @return 
     */
    public ConfigStrategyChain<T,C> entity(BiPredicate<T, StrategyMode> entityFunction, ImmutablePair<T, StrategyMode> argument){
        if(!isContinue()){
            return this;
        }
        //
        try{
            if(entityFunction.test(argument.getLeft(), argument.getRight())){
                return new ConfigStrategyChain<>(true, null);
            }
        }catch(StrategyException e){
            return new ConfigStrategyChain<>(false, e);
        }
        return new ConfigStrategyChain<>(false, new StrategyException("实体检测失败"));
    }
    /**
     * 
     * @param culpritorFunction 操作者/会员检谓词函数
     * @param argument 操作者/会员检谓词函数参数
     * @return 
     */
    public ConfigStrategyChain<T,C> culpritor(TriPredicate<C, Member, StrategyMode> culpritorFunction, ImmutableTriple<C, Member, StrategyMode> argument){
        if(!isContinue()){
            return this;
        }
        //
        try{
            if(culpritorFunction.test(argument.getLeft(), argument.getMiddle(), argument.getRight())){
                return new ConfigStrategyChain<>(true, null);
            }
        }catch(StrategyException e){
            return new ConfigStrategyChain<>(false, e);
        }
        return new ConfigStrategyChain<>(false, new StrategyException("操作者检测失败"));
    }
    
    public boolean isContinue() {
        return result;
    }
    
    public Optional<StrategyException> getBreakException() {
        return Optional.ofNullable(exception);
    }
}
