using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Windows;
using Machinations.FromFlash.graph;
using Machinations.FromFlash.utils;

namespace Machinations.FromFlash.machinations.model
{
    /// <summary>
    /// description of connections, dictating behaviour of connections
    /// </summary>
    public class Label
    {
        private string m_text;
        private string m_preIntervalText;
        private List<string> m_postFix;
        private List<string> m_postFixInterval;
        private double m_value;
        private string m_intervalText;
        private double m_probability;
        private double m_inputStateValue;
        private double m_inputStateInterval;
        private int m_interval;
        private double m_rangeTop;
        private double m_rest;
        private int m_multiplier;
        private int m_originalMultiplier;

        public double Position;
        public MachinationsConnection Connection;
        public Point CalculatedPosition;
        public Point Size;
        public int Side = 1;
        public LabelType Type;
        public LabelType IntervalType;
        //private var _changeValue:Number;

        public bool DrawRandom;

        public List<double> GeneratedValues;
        public const double Limit = 9999;

        public double Min = -Limit;
        public double Max = Limit;

        private const int MaxDigit = 3;
        private const int MaxProbabilityDigit = 1;
        private const int MaxMultiplierDigit = 0;

        public Label(MachinationsConnection connection, double position, string text)
        {
            GeneratedValues = new List<double>();
            Connection = connection;
            Position = position;
            Text = text;
            Size = new Point();
            m_inputStateInterval = 0;
            m_inputStateValue = 0;
            m_preIntervalText = "";
            m_intervalText = "";
            m_rest = 0;
            DrawRandom = false;
            m_multiplier = -1;
            m_originalMultiplier = m_multiplier;
        }

        /// <summary>
        /// nevraci m_text, pro ten pouzit property normal text
        /// </summary>
        public string Text
        {
            get
            {
                if (m_text == "") return "";
                string t;
                switch (Type)
                {
                    case LabelType.None:
                        return m_text;
                    case LabelType.Dice:
                    case LabelType.Skill:
                    case LabelType.Multiplayer:
                    case LabelType.Strategy:
                        //t = "   " + GetIntervalText();
                        //return t;
                        return m_text;
                }

                t = m_preIntervalText;
                if (m_inputStateValue != 0)
                {
                    double v;
                    switch (Type)
                    {
                        case LabelType.FixedValue:
                            v = double.Parse(m_postFix[0], CultureInfo.InvariantCulture);
                            v += m_inputStateValue;
                            v = Math.Round(v * 100) / 100;
                            v = Math.Max(Min, (Math.Min(Max, v)));

                            t = StringUtils.FloatToStringMaxPrecision(v, MaxDigit);
                            break;
                        case LabelType.CalculatedValue:
                            v = Math.Round(m_inputStateValue);
                            v = Math.Max(Min, (Math.Min(Max, v)));
                            if (v < 0) t = (m_preIntervalText + StringUtils.FloatToStringMaxPrecision(v, MaxDigit));
                            else if (v > 0) t = (m_preIntervalText + "+" + StringUtils.FloatToStringMaxPrecision(v, MaxDigit));
                            break;
                        case LabelType.Probability:
                            v = m_probability + Math.Round(m_inputStateValue);
                            v = Math.Max(Min, (Math.Min(Max, v)));
                            t = (StringUtils.FloatToStringMaxPrecision(v, MaxProbabilityDigit) + "%");
                            break;
                        case LabelType.ProbabilityDynamic:
                            v = m_probability;
                            v = Math.Max(Min, (Math.Min(Max, v)));
                            if (v < 0) t = "%";
                            else t = (StringUtils.FloatToStringMaxPrecision(v, MaxProbabilityDigit) + "%");
                            break;
                        case LabelType.ChangeValue:
                            //v = _changeValue + m_inputStateValue;
                            v = m_value + m_inputStateValue;
                            v = Math.Max(Min, (Math.Min(Max, v)));
                            if (v < 0) t = (StringUtils.FloatToStringMaxPrecision(v, MaxDigit));
                            else t = ("+" + StringUtils.FloatToStringMaxPrecision(v, MaxDigit));
                            break;
                        case LabelType.ChangeInterval:
                            //v = Math.Round(_changeValue + m_inputStateValue);
                            v = Math.Round(m_value + m_inputStateValue);
                            v = Math.Max(Min, (Math.Min(Max, v)));
                            if (v < 0) t = (StringUtils.FloatToStringMaxPrecision(v, MaxMultiplierDigit) + "i");
                            else t = ("+" + StringUtils.FloatToStringMaxPrecision(v, MaxMultiplierDigit) + "i");
                            break;
                        case LabelType.ChangeProbability:
                            //v = _changeValue + m_inputStateValue;
                            v = m_value + m_inputStateValue;
                            v = Math.Max(Min, (Math.Min(Max, v)));
                            if (v < 0) t = (StringUtils.FloatToStringMaxPrecision(v, MaxProbabilityDigit) + "%");
                            else t = ("+" + StringUtils.FloatToStringMaxPrecision(v, MaxProbabilityDigit) + "%");
                            break;
                        case LabelType.ChangeMultiplier:
                            //v = _changeValue + m_inputStateValue;
                            v = m_value + m_inputStateValue;
                            v = Math.Max(Min, (Math.Min(Max, v)));
                            if (v < 0) t = (StringUtils.FloatToStringMaxPrecision(v, MaxMultiplierDigit) + "m");
                            else t = ("+" + StringUtils.FloatToStringMaxPrecision(v, MaxMultiplierDigit) + "m");
                            break;
                        case LabelType.ChangeCapacity:
                            //v = _changeValue + m_inputStateValue;
                            v = m_value + m_inputStateValue;
                            v = Math.Max(Min, (Math.Min(Max, v)));
                            if (v < 0) t = (StringUtils.FloatToStringMaxPrecision(v, MaxMultiplierDigit) + "c");
                            else t = ("+" + StringUtils.FloatToStringMaxPrecision(v, MaxMultiplierDigit) + "c");
                            break;
                        case LabelType.EqualTo:
                            v = m_value + m_inputStateValue;
                            v = Math.Max(Min, (Math.Min(Max, v)));
                            t = "==" + StringUtils.FloatToStringMaxPrecision(v, 0);
                            break;
                        case LabelType.NotEqualTo:
                            v = m_value + m_inputStateValue;
                            v = Math.Max(Min, (Math.Min(Max, v)));
                            t = "!=" + StringUtils.FloatToStringMaxPrecision(v, 0);
                            break;
                        case LabelType.LessOrEqual:
                            v = m_value + m_inputStateValue;
                            v = Math.Max(Min, (Math.Min(Max, v)));
                            t = "<=" + StringUtils.FloatToStringMaxPrecision(v, 0);
                            break;
                        case LabelType.Less:
                            v = m_value + m_inputStateValue;
                            v = Math.Max(Min, (Math.Min(Max, v)));
                            t = "<" + StringUtils.FloatToStringMaxPrecision(v, 0);
                            break;
                        case LabelType.GreaterOrEqual:
                            v = m_value + m_inputStateValue;
                            v = Math.Max(Min, (Math.Min(Max, v)));
                            t = ">=" + StringUtils.FloatToStringMaxPrecision(v, 0);
                            break;
                        case LabelType.Greater:
                            v = m_value + m_inputStateValue;
                            v = Math.Max(Min, (Math.Min(Max, v)));
                            t = ">" + StringUtils.FloatToStringMaxPrecision(v, 0);
                            break;
                        case LabelType.Trigger:
                            t = "!";
                            break;
                        //case LabelType.Trigger:
                        //    t = "*";
                        //    break;
                        case LabelType.All:
                            t = "all";
                            break;
                    }
                }
                t += GetIntervalText();
                if (DrawRandom && t.SafeSubstring(0, 4) != "draw") t = "draw" + t;
                if (m_originalMultiplier >= 0)
                {
                    t = m_multiplier + "*" + t;
                }
                return t;
            }
            set
            {
                m_text = value;
                try
                {
                    DetermineType();
                }
                catch (Exception e)
                {
                    Type = LabelType.None;
                }
                GenerateNewValue();
                SetNewInterval();
            }
        }

        public string RealText
        {
            get { return m_text; }
            set { Text = value; }
        }

        public double InputStateValue
        {
            get { return m_inputStateValue; }
        }

        public string NormalText()
        {
            return m_text;
        }

        public double Value
        {
            get
            {
                if (Connection is ResourceConnection && IntervalType != LabelType.None)
                {
                    if (m_interval > 1)
                    {
                        m_interval--;
                        return 0;
                    }
                    SetNewInterval();
                }
                switch (Type)
                {
                    case LabelType.ProbabilityDynamic:
                    case LabelType.Probability:
                        if (Connection.Start is Gate) return Math.Max(Min, (Math.Min(Max, m_probability + m_inputStateValue)));
                        return Math.Max(Min, (Math.Min(Max, m_value)));
                    case LabelType.All:
                        if (Connection.Start is Pool)
                        {
                            if ((Connection.Start as Pool).Color != Connection.Color)
                            {
                                m_value = Math.Max(0, Math.Max(Min, (Math.Min(Max, (Connection.Start as Pool).ResourceColorCount(Connection.Color)))));
                            }
                            else
                            {
                                m_value = Math.Max(0, Math.Max(Min, (Math.Min(Max, (Connection.Start as Pool).ResourceCount))));
                            }
                            GeneratedValues.Add(m_value);
                            return m_value;
                        }
                        return 0;
                    case LabelType.ChangeValue:
                    case LabelType.ChangeInterval:
                    case LabelType.ChangeProbability:
                        double v = m_value + m_inputStateValue;
                        return Math.Max(Min, (Math.Min(Max, v)));
                    default:
                        return Math.Max(Min, (Math.Min(Max, m_value)));
                }
            }
        }

        public string IntervalText
        {
            get { return m_intervalText; }
        }

        public int Interval
        {
            get { return m_interval; }
        }

        public void GenerateNewValue()
        {
            GeneratedValues.Clear();

            switch (Type)
            {
                case LabelType.EqualTo:
                case LabelType.Greater:
                case LabelType.GreaterOrEqual:
                case LabelType.ChangeInterval:
                case LabelType.ChangeValue:
                case LabelType.ChangeProbability:
                case LabelType.ChangeMultiplier:
                case LabelType.ChangeCapacity:
                case LabelType.All:
                case LabelType.Less:
                case LabelType.LessOrEqual:
                case LabelType.NotEqualTo:
                case LabelType.Range:
                case LabelType.Trigger:
                case LabelType.ReverseTrigger:
                case LabelType.ProbabilityDynamic:
                    GeneratedValues.Add(m_value);
                    return;
                case LabelType.None:
                    m_value = 1;
                    GeneratedValues.Add(m_value);
                    return;
                case LabelType.Else:
                    m_value = 1;
                    GeneratedValues.Add(m_value);
                    return;
                case LabelType.Dice:
                    if (Connection.Graph != null) m_value = ((MachinationsGraph)Connection.Graph).GetDiceValue() + m_inputStateValue;
                    GeneratedValues.Add(m_value);
                    return;
                case LabelType.Skill:
                    if (Connection.Graph != null) m_value = ((MachinationsGraph)Connection.Graph).GetSkillValue() + m_inputStateValue;
                    GeneratedValues.Add(m_value);
                    return;
                case LabelType.Multiplayer:
                    if (Connection.Graph != null) m_value = ((MachinationsGraph)Connection.Graph).GetMultiplayerValue() + m_inputStateValue;
                    GeneratedValues.Add(m_value);
                    return;
                case LabelType.Strategy:
                    if (Connection.Graph != null) m_value = ((MachinationsGraph)Connection.Graph).GetStrategyValue() + m_inputStateValue;
                    GeneratedValues.Add(m_value);
                    return;
            }
            m_value = 0;
            int m = m_multiplier;
            if (m_originalMultiplier < 0)
            {
                m = 1;
            }


            for (int i = 0; i < m; i++)
            {
                switch (Type)
                {
                    case LabelType.FixedValue:
                        double v = double.Parse(m_postFix[0], CultureInfo.InvariantCulture);
                        v += m_inputStateValue;
                        if (Connection is ResourceConnection)
                        {
                            v += m_rest;
                            m_value += Math.Floor(v);
                            GeneratedValues.Add(Math.Floor(v));
                            m_rest = v % 1;
                        }
                        else
                        {
                            m_value += v;
                            GeneratedValues.Add(v);
                        }
                        break;
                    case LabelType.CalculatedValue:
                    case LabelType.DynamicDice:
                        v = MachinationsExpression.EvaluatePostFix(m_postFix);
                        v += m_inputStateValue;
                        if (Connection is ResourceConnection)
                        {
                            v += m_rest;
                            m_value += Math.Floor(v);
                            GeneratedValues.Add(Math.Floor(v));
                            m_rest = v % 1;
                        }
                        else
                        {
                            m_value += v;
                            GeneratedValues.Add(v);
                        }
                        break;
                    case LabelType.Probability:
                        double p = m_probability + m_inputStateValue;
                        v = 0;
                        while (p > 100)
                        {
                            v += 1;
                            p -= 100;
                        }
                        double randomVal = RandomUtils.NextDouble() * 100;
                        if (randomVal < p)
                        {
                            v++;
                        }
                        m_value += v;
                        GeneratedValues.Add(v);
                        break;
                }

            }
        }

        public void Prepare()
        {
            DetermineType();
            m_inputStateValue = 0;
            m_inputStateInterval = 0;
            m_rest = 0;
            GenerateNewValue();

            SetNewInterval();
        }

        public void Reset()
        {
            m_inputStateValue = 0;
        }

        public void DetermineType()
        {
            try
            {
                string text = m_text;
                DrawRandom = false;
                //int dice;
                //var p2:int;
                IntervalType = LabelType.None;
                if (text == "")
                {
                    if (Connection is ResourceConnection)
                    {
                        Type = LabelType.None;
                        GenerateNewValue();
                    }
                    else
                    {
                        Type = LabelType.ChangeValue;
                        m_value = 1;
                    }
                    return;
                }

                var p = text.IndexOf("*", StringComparison.Ordinal);
                if (p > 0)
                {
                    m_multiplier = int.Parse(text.Substring(0, p));
                    text = text.Substring(p + 1);
                }
                else
                {
                    m_multiplier = -1;
                }
                m_originalMultiplier = m_multiplier;

                p = text.IndexOf("/");
                if (p >= 0)
                {
                    m_preIntervalText = text.Substring(0, p);
                    m_intervalText = text.Substring(p + 1);
                    text = m_preIntervalText;
                    m_postFixInterval = MachinationsExpression.ToPostFix(IntervalText);
                    if (m_postFixInterval.Count == 1)
                    {
                        IntervalType = LabelType.FixedValue;
                    }
                    else
                    {
                        IntervalType = LabelType.CalculatedValue;
                    }
                }
                else
                {
                    m_preIntervalText = text;
                    m_intervalText = "";
                }

                if (text.SafeSubstring(0, 4) == "draw")
                {
                    DrawRandom = true;
                    text = text.Substring(4);
                }
                if (text == "*")
                {
                    Type = LabelType.Trigger;
                    m_value = 0;
                }
                else if (text == "!")
                {
                    Type = LabelType.ReverseTrigger;
                    m_value = 0;
                }
                else if (text == "%")
                {
                    Type = LabelType.ProbabilityDynamic;
                    m_probability = -1;
                    m_value = 0;
                }
                else if (text.ToLower() == "else")
                {
                    Type = LabelType.Else;
                    m_probability = 0;
                    m_value = 0;
                }
                else if (text.ToLower() == "all")
                {
                    Type = LabelType.All;
                    m_probability = 0;
                    m_value = 0;
                }
                else if (text == "D" /*|| text.toLowerCase() == "dice"*/)
                {
                    Type = LabelType.Dice;
                }
                else if (text == "S" /*|| text.toLowerCase() == "skill"*/)
                {
                    Type = LabelType.Skill;
                }
                else if (text == "ST" /*|| text.toLowerCase() == "strategy"*/)
                {
                    Type = LabelType.Strategy;
                }
                else if (text == "M" /*|| text.toLowerCase() == "multiplayer"*/)
                {
                    Type = LabelType.Multiplayer;
                }
                else if (text.SafeSubstring(0, 2) == "==")
                {
                    Type = LabelType.EqualTo;
                    m_value = double.Parse(text.Substring(2), CultureInfo.InvariantCulture);
                }
                else if (text.SafeSubstring(0, 2) == "!=")
                {
                    Type = LabelType.NotEqualTo;
                    m_value = double.Parse(text.Substring(2), CultureInfo.InvariantCulture);
                }
                else if (text.SafeSubstring(0, 2) == "<=")
                {
                    Type = LabelType.LessOrEqual;
                    m_value = double.Parse(text.Substring(2), CultureInfo.InvariantCulture);
                }
                else if (text.SafeSubstring(0, 2) == ">=")
                {
                    Type = LabelType.GreaterOrEqual;
                    m_value = double.Parse(text.Substring(2), CultureInfo.InvariantCulture);
                }
                else if (text.SafeSubstring(0, 1) == "<")
                {
                    Type = LabelType.Less;
                    m_value = double.Parse(text.Substring(1), CultureInfo.InvariantCulture);
                }
                else if (text.SafeSubstring(0, 1) == ">")
                {
                    Type = LabelType.Greater;
                    m_value = double.Parse(text.Substring(1), CultureInfo.InvariantCulture);
                }
                else if ((Connection.Start is Gate || Connection is StateConnection) && text.IndexOf('-') > 0)
                {
                    Type = LabelType.Range;
                    p = text.IndexOf('-');
                    m_value = double.Parse(text.Substring(0, p), CultureInfo.InvariantCulture);
                    m_rangeTop = double.Parse(text.Substring(p + 1), CultureInfo.InvariantCulture);
                }
                else if (text[0] == '+' || (text[0] == '-' && Connection is StateConnection))
                {
                    Type = LabelType.ChangeValue;
                    p = text.IndexOf('m');
                    if (p >= 0)
                    {
                        Type = LabelType.ChangeMultiplier;
                        text = text.Substring(0, p);
                    }
                    p = text.IndexOf('c');
                    if (p >= 0)
                    {
                        Type = LabelType.ChangeCapacity;
                        text = text.Substring(0, p);
                    }
                    p = text.IndexOf('i');
                    if (p >= 0)
                    {
                        Type = LabelType.ChangeInterval;
                        text = text.Substring(0, p);
                    }
                    p = text.IndexOf('%');
                    if (p >= 0)
                    {
                        Type = LabelType.ChangeProbability;
                        text = text.Substring(0, p);
                    }
                    //changeValue = double.Parse(text.Substring(1), CultureInfo.InvariantCulture);
                    m_value = double.Parse(text.Substring(1), CultureInfo.InvariantCulture);
                    if (text[0] == '-') m_value *= -1;
                }
                else if (text.IndexOf('%') > 0)
                {
                    Type = LabelType.Probability;
                    m_probability = double.Parse(text.Substring(0, text.IndexOf('%')), CultureInfo.InvariantCulture);
                    if (double.IsNaN(m_probability)) m_probability = 0;
                }
                else
                {
                    m_postFix = MachinationsExpression.ToPostFix(text);
                    if (m_postFix.Count == 1)
                    {
                        Type = LabelType.FixedValue;
                    }
                    else if (m_postFix.Count != 0)
                    {
                        if (m_postFix.Last().ToUpper().Equals("D"))
                            Type = LabelType.DynamicDice;
                        else
                            Type = LabelType.CalculatedValue;
                    }
                    else Type = LabelType.CalculatedValue;
                }
            }
            catch (FormatException)
            {
                m_text = "LoadError";
            }

        }

        //public void RestoreText(string text)
        //{
        //    m_inputStateValue = text;
        //}

        public void Stop()
        {
            m_inputStateValue = 0;
            m_inputStateInterval = 0;
            m_multiplier = m_originalMultiplier;
        }

        public void Modify(double delta)
        {
            m_inputStateValue += delta;
            Recalculate();
        }

        public double[] Save()
        {
            return new[] { m_value, m_inputStateValue };
        }

        public void Restore(double[] savedValues)
        {
            m_value = savedValues[0];
            m_inputStateValue = savedValues[1];
            Recalculate();
        }

        private void Recalculate()
        {
            GenerateNewValue();
            if (Connection.DoEvents) Connection.OnChanged(GraphEvent.ElementChange);
            if ((Connection.Start is Gate) && Type == LabelType.Probability)
            {
                (Connection.Start as Gate).CheckDynamicProbabilities();
            }
            if (IsCondition() && Connection is StateConnection)
            {
                (Connection as StateConnection).Inhibited = !CheckCondition((Connection as StateConnection).State);
            }
            /*
			//Changes to label modifiers immediately take effect, maybe this should be an optional setting. 
			switch (Type) {
				case TYPE_CHANGE_VALUE:
				case TYPE_CHANGE_INTERVAL:
				case TYPE_CHANGE_PROBABILITY:
					if (Connection is StateConnection) {
						(Connection as StateConnection).changeModifier(delta);
					}
					break;
			}
			//*/
        }

        public void ModifyInterval(int delta)
        {
            m_inputStateInterval += delta;

            GenerateNewValue();
            if (Connection.DoEvents) Connection.OnChanged(GraphEvent.ElementChange);
        }

        public void ModifyMultiplier(int delta)
        {
            m_multiplier += delta;

            GenerateNewValue();
            if (Connection.DoEvents) Connection.OnChanged(GraphEvent.ElementChange);
        }

        public bool IsCondition()
        {
            switch (Type)
            {
                case LabelType.Greater:
                case LabelType.GreaterOrEqual:
                case LabelType.EqualTo:
                case LabelType.Less:
                case LabelType.LessOrEqual:
                case LabelType.NotEqualTo:
                case LabelType.Range:
                case LabelType.Else:
                    return true;
            }
            return false;
        }

        public bool CheckCondition(double value)
        {
            //if (Connection.Graph == null || !((MachinationsGraph)Connection.Graph).Running) return true;
            if ((Connection.Graph as MachinationsGraph)?.Running == false)
                return true;
            switch (Type)
            {
                case LabelType.Greater:
                    return (value > (m_value + m_inputStateValue));
                case LabelType.GreaterOrEqual:
                    return (value >= (m_value + m_inputStateValue));
                case LabelType.EqualTo:
                    return (value == m_value + m_inputStateValue);
                case LabelType.Less:
                    return (value < (m_value + m_inputStateValue));
                case LabelType.LessOrEqual:
                    return (value <= m_value + m_inputStateValue);
                case LabelType.NotEqualTo:
                    return (value != m_value + m_inputStateValue);
                case LabelType.Range:
                    return (value >= m_value && value <= m_rangeTop);
                case LabelType.FixedValue:
                    return (value == m_value + m_inputStateValue);
                case LabelType.Else:
                    return false;
            }
            return false;
        }

        public void SetDynamicProbability(double prob)
        {
            if (prob != m_probability)
            {
                m_probability = prob;
                m_inputStateValue = 1;
                if (Connection.DoEvents) Connection.OnChanged(GraphEvent.ElementChange);
            }
        }

        public string GetMMText()
        {
            //TODO: solve hyperedge problem.

            if (!Connection.Inputs.Any())
                return m_text;
            StringBuilder text = new StringBuilder(m_text);
            text.Append(Connection.GetMMExp());
            return text.ToString();
        }

        private string GetIntervalText()
        {
            StringBuilder t = new StringBuilder();
            if (string.IsNullOrEmpty(m_intervalText)) t.Append("");
            else t.Append("/" + m_intervalText);
            int v;
            if (m_inputStateInterval != 0)
            {
                switch (IntervalType)
                {
                    case LabelType.FixedValue:
                        v = int.Parse(m_postFixInterval[0]) + Convert.ToInt32(m_inputStateInterval);
                        t.Append("/" + (v));
                        break;
                    case LabelType.CalculatedValue:
                        v = Convert.ToInt32(Math.Round(m_inputStateInterval));
                        if (v < 0) t.Append(m_intervalText + v);
                        else if (v > 0) t.Append("/" + (m_intervalText + "+" + v));
                        break;
                }
            }
            return t.ToString();
        }

        private void SetNewInterval()
        {
            switch (IntervalType)
            {
                //default:
                case LabelType.None:
                    m_interval = 1;
                    break;
                case LabelType.FixedValue:
                    m_interval = int.Parse(m_postFixInterval[0]) + Convert.ToInt32(m_inputStateInterval);
                    break;
                case LabelType.CalculatedValue:
                    m_interval = Convert.ToInt32(MachinationsExpression.EvaluatePostFix(m_postFixInterval) + m_inputStateInterval);
                    break;
            }
        }
    }

    public enum LabelType
    {
        None,
        CalculatedValue,
        FixedValue,
        ChangeValue,
        ChangeInterval,
        ChangeProbability,
        ChangeMultiplier,
        ChangeCapacity,
        Probability,
        ProbabilityDynamic,
        EqualTo,
        NotEqualTo,
        Less,
        Greater,
        LessOrEqual,
        GreaterOrEqual,
        Range,
        Dice,
        Skill,
        Multiplayer,
        Strategy,
        Trigger,
        ReverseTrigger,
        Else,
        All,
        DynamicDice
    }



}
