package com.brilliance.mda.runtime.mda.util;

import com.brilliance.mda.runtime.mda.*;

import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class RuleUtils {

    static Comparator<IRule> c = new Comparator<IRule>() {
        public int compare(IRule rule1, IRule rule2) {
            return rule1.getOrder() - rule2.getOrder();
        }
    };

    static Comparator<IEventRule> c2 = new Comparator<IEventRule>() {
        public int compare(IEventRule rule1, IEventRule rule2) {
            if (rule1.getType().equals(rule2.getType()))
                return rule1.getOrder() - rule2.getOrder();
            return rule1.getType().compareTo(rule2.getType());
        }
    };

    public static final void sort(List<IRule> rules) {
        if (rules != null)
            Collections.sort(rules, c);
    }

    public static final InheritableThreadLocal<IContext> ctx = new InheritableThreadLocal<IContext>();

    public static final boolean invoke(List<IRule> rules, IContext ctx, IAttributeValue av) {
        if (rules == null)
            return true;
        boolean continued = true;
        RuleUtils.ctx.set(ctx);
        for (int i = 0; continued && i < rules.size(); i++) {
            try {
                continued = ((IRule) rules.get(i)).invoke(ctx, av);
            } catch (Throwable e) {
                if (!(e instanceof ExitEventException))
                continued = false;
            }
        }
        return continued;
    }

    public static final void sort2(List<IEventRule> rules) {
        if (rules != null)
            Collections.sort(rules, c2);
    }

    public static final boolean invoke(List<IEventRule> rules, IContext ctx, Event event, int... orders) {
        if (rules == null)
            return true;
        boolean continued = true;
        RuleUtils.ctx.set(ctx);
        boolean checkMinOrder = (orders != null && orders.length > 0);
        boolean checkMaxOrder = (orders != null && orders.length > 1);
        int minOrder = checkMinOrder ? orders[0] : 0;
        int maxOrder = checkMaxOrder ? orders[1] : 0;
        for (IEventRule rule : rules) {
            if (rule.getType() == EventType.DEFAULT || rule.getType() == event.getType()) {
                if ((checkMinOrder && rule.getOrder() < minOrder) || (checkMaxOrder && rule.getOrder() > maxOrder))
                    continue;
                try {
                    continued = rule.invoke(ctx, event);
                } catch (Throwable e) {
                    if (!(e instanceof ExitEventException))
                    continued = false;
                }
                if (!continued)
                    break;
            }
        }
        return continued;
    }
}
