using System;
using System.Collections.Generic;
using Aitex.Core.RT.DataCenter;
using Aitex.Core.RT.SCCore;
using Aitex.Core.Util;
using DocumentFormat.OpenXml.Spreadsheet;
namespace Aitex.Core.RT.IOCore
{
    /*
     * 
  
    
  
     * 
     */
    public abstract class InterlockLimit
    {
        public string Name
        {
            get { return _name; }
        }
        public abstract bool CurrentValue { get; }
        public abstract string LimitReason { get; }
        public bool LimitValue
        {
            get { return _limitValue; }
        }
        public string Tip
        {
            get
            {
                return _tip;
            }
        }
        public string Condition { get; set; }//AND,OR,EXOR,BLANK
        public bool IsFloatType { get; set; }
        private string _name;
        private bool _limitValue;
        private string _tip;
        private Dictionary _cultureTip = new Dictionary();
        R_TRIG _trigger = new R_TRIG();
        public InterlockLimit(string name, bool value, string tip, Dictionary cultureTip)
        {
            _name = name;
            _limitValue = value;
            _tip = tip;
            _cultureTip = cultureTip;
        }
        public bool IsSame(string name, bool value)
        {
            return (name == _name) && (_limitValue == value);
        }
        public bool IsSame(InterlockLimit limit)
        {
            return (limit.Name == _name) && (_limitValue == limit.LimitValue);
        }
        public bool IsTriggered()
        {
            _trigger.CLK = CurrentValue != _limitValue;
            return _trigger.Q;
        }
        public bool CanDo(out string reason)
        {
            reason = string.Empty;
            if (CurrentValue == _limitValue)
                return true;
            reason = LimitReason;
            return false;
        }
    }
    internal class DiLimit : InterlockLimit
    {
        private DIAccessor _di;
        public DiLimit(DIAccessor diItem, bool value, string tip, Dictionary cultureTip, string condition = "AND")
        : base(diItem.Name, value, tip, cultureTip)
        {
            _di = diItem;
            Condition = condition;
        }
        public DiLimit(DIAccessor diItem, bool value, string condition)
        : base(diItem.Name, value, "", null)
        {
            _di = diItem;
            Condition = condition;
        }
        public override bool CurrentValue
        {
            get { return _di.Value; }
        }
        public override string LimitReason
        {
            get
            {
                return string.Format("DI-{0}({1}) = [{2}],{3}", _di.IoTableIndex, _di.Name, _di.Value ? "ON" : "OFF", Tip);
            }
        }
    }
    internal class DoLimit : InterlockLimit
    {
        private DOAccessor _do;
        public DoLimit(DOAccessor doItem, bool value, string tip, Dictionary cultureTip, string condition = "AND")
            : base(doItem.Name, value, tip, cultureTip)
        {
            _do = doItem;
            Condition = condition;
        }
        public DoLimit(DOAccessor doItem, bool value, string condition)
        : base(doItem.Name, value, "", null)
        {
            _do = doItem;
            Condition = condition;
        }
        public override bool CurrentValue
        {
            get { return _do.Value; }
        }
        public override string LimitReason
        {
            get
            {
                return string.Format("DO-{0}({1}) = [{2}],{3}", _do.IoTableIndex, _do.Name, _do.Value ? "ON" : "OFF", Tip);
            }
        }
    }
    internal class AoLimit : InterlockLimit
    {
        /// 
        //LT(less than)               小于
        //LE(less than or equal to)   小于等于
        //EQ(equal to)                等于
        //NE(not equal to)            不等于
        //GE(greater than or equal to)大于等于
        //GT(greater than)            大于
        //B(bool) 
        /// 
        private AOAccessor _ao;
        private float _limitFloatValue;
        private string _operator;
        private string _module = "";
        public AoLimit(AOAccessor aoItem, string value, string condition, bool isFloatType = true)
        : base(aoItem.Name, true, "", null)
        {
            _ao = aoItem;
            Condition = condition;
            IsFloatType = isFloatType;
            //if (value.StartsWith(">="))
            //{
            //    _operator = ">=";
            //}
            //else if (value.StartsWith("<="))
            //{
            //    _operator = "<=";
            //}
            //else if (value.StartsWith(">"))
            //{
            //    _operator = ">";
            //}
            //else if (value.StartsWith("<"))
            //{
            //    _operator = "<";
            //}
            //else
            //{
            //    _operator = "=";
            //}
            if (value.Contains("GT"))
            {
                _operator = "GT";
            }
            else if (value.Contains("GE"))
            {
                _operator = "GE";
            }
            else if (value.Contains("NE"))
            {
                _operator = "NE";
            }
            else if (value.Contains("EQ"))
            {
                _operator = "EQ";
            }
            else if (value.Contains("LE"))
            {
                _operator = "LE";
            }
            else if (value.Contains("LT"))
            {
                _operator = "LT";
            }
            float.TryParse(value.Replace(_operator, ""), out _limitFloatValue);
            var paras = aoItem.Name.Split('.');
            if (paras != null && paras.Length > 1)
                _module = paras[0];
        }
        public override string LimitReason
        {
            get
            {
                return string.Format("AO-{0}({1}) = [{2}],{3}", _ao.IoTableIndex, _ao.Name, (SC.ContainsItem($"{_module}.IsAIAOFloatType") && SC.GetValue($"{_module}.IsAIAOFloatType") ? _ao.FloatValue : _ao.Value), Tip);
            }
        }
        public override bool CurrentValue
        {
            get
            {
                switch (_operator)
                {
                    case "GT":
                        return (SC.ContainsItem($"{_module}.IsAIAOFloatType") && SC.GetValue($"{_module}.IsAIAOFloatType") ? _ao.FloatValue : _ao.Value) > _limitFloatValue;
                    case "GE":
                        return (SC.ContainsItem($"{_module}.IsAIAOFloatType") && SC.GetValue($"{_module}.IsAIAOFloatType") ? _ao.FloatValue : _ao.Value) >= _limitFloatValue;
                    case "NE":
                        return (SC.ContainsItem($"{_module}.IsAIAOFloatType") && SC.GetValue($"{_module}.IsAIAOFloatType") ? _ao.FloatValue : _ao.Value) != _limitFloatValue;
                    case "EQ":
                        return Math.Abs((SC.ContainsItem($"{_module}.IsAIAOFloatType") && SC.GetValue($"{_module}.IsAIAOFloatType") ? _ao.FloatValue : _ao.Value) - _limitFloatValue) < 0.000001;
                    case "LE":
                        return (SC.ContainsItem($"{_module}.IsAIAOFloatType") && SC.GetValue($"{_module}.IsAIAOFloatType") ? _ao.FloatValue : _ao.Value) <= _limitFloatValue;
                    case "LT":
                        return (SC.ContainsItem($"{_module}.IsAIAOFloatType") && SC.GetValue($"{_module}.IsAIAOFloatType") ? _ao.FloatValue : _ao.Value) < _limitFloatValue;
                    default:
                        return false;
                }
            }
        }
    }
    internal class AiLimit : InterlockLimit
    {
        /// 
        //LT(less than)               小于
        //LE(less than or equal to)   小于等于
        //EQ(equal to)                等于
        //NE(not equal to)            不等于
        //GE(greater than or equal to)大于等于
        //GT(greater than)            大于
        //B(bool) 
        /// 
        private AIAccessor _ai;
        private float _limitFloatValue;
        private string _operator;
        private string _module = "";
        public AiLimit(AIAccessor aiItem, string value, string condition, bool isFloatType = true)
        : base(aiItem.Name, true, "", null)
        {
            _ai = aiItem;
            Condition = condition;
            IsFloatType = isFloatType;
            //if (value.StartsWith(">="))
            //{
            //    _operator = ">=";
            //}
            //else if (value.StartsWith("<="))
            //{
            //    _operator = "<=";
            //}
            //else if (value.StartsWith(">"))
            //{
            //    _operator = ">";
            //}
            //else if (value.StartsWith("<"))
            //{
            //    _operator = "<";
            //}
            //else
            //{
            //    _operator = "=";
            //}
            if (value.Contains("GT"))
            {
                _operator = "GT";
            }
            else if (value.Contains("GE"))
            {
                _operator = "GE";
            }
            else if (value.Contains("NE"))
            {
                _operator = "NE";
            }
            else if (value.Contains("EQ"))
            {
                _operator = "EQ";
            }
            else if (value.Contains("LE"))
            {
                _operator = "LE";
            }
            else if (value.Contains("LT"))
            {
                _operator = "LT";
            }
            float.TryParse(value.Replace(_operator, ""), out _limitFloatValue);
            var paras = aiItem.Name.Split('.');
            if (paras != null && paras.Length > 1)
                _module = paras[0];
        }
        public override string LimitReason
        {
            get
            {
                return string.Format("AO-{0}({1}) = [{2}],{3}", _ai.IoTableIndex, _ai.Name, (SC.ContainsItem($"{_module}.IsAIAOFloatType") && SC.GetValue($"{_module}.IsAIAOFloatType") ? _ai.FloatValue : _ai.Value), Tip);
            }
        }
        public override bool CurrentValue
        {
            get
            {
                switch (_operator)
                {
                    case "GT":
                        return (SC.ContainsItem($"{_module}.IsAIAOFloatType") && SC.GetValue($"{_module}.IsAIAOFloatType") ? _ai.FloatValue : _ai.Value) > _limitFloatValue;
                    case "GE":
                        return (SC.ContainsItem($"{_module}.IsAIAOFloatType") && SC.GetValue($"{_module}.IsAIAOFloatType") ? _ai.FloatValue : _ai.Value) >= _limitFloatValue;
                    case "NE":
                        return (SC.ContainsItem($"{_module}.IsAIAOFloatType") && SC.GetValue($"{_module}.IsAIAOFloatType") ? _ai.FloatValue : _ai.Value) != _limitFloatValue;
                    case "EQ":
                        return Math.Abs((SC.ContainsItem($"{_module}.IsAIAOFloatType") && SC.GetValue($"{_module}.IsAIAOFloatType") ? _ai.FloatValue : _ai.Value) - _limitFloatValue) < 0.000001;
                    case "LE":
                        return (SC.ContainsItem($"{_module}.IsAIAOFloatType") && SC.GetValue($"{_module}.IsAIAOFloatType") ? _ai.FloatValue : _ai.Value) <= _limitFloatValue;
                    case "LT":
                        return (SC.ContainsItem($"{_module}.IsAIAOFloatType") && SC.GetValue($"{_module}.IsAIAOFloatType") ? _ai.FloatValue : _ai.Value) < _limitFloatValue;
                    default:
                        return false;
                }
            }
        }
    }
    internal class UserDefineLimit : InterlockLimit
    {
        public UserDefineLimit(string name, bool limitValue, string condition)
            : base(name, limitValue, "", null)
        {
            Condition = condition;
        }
        public override bool CurrentValue { get; }
        public override string LimitReason { get; }
    }
    internal class DataPollLimit : InterlockLimit
    {
        /// 
        //LT(less than)               小于
        //LE(less than or equal to)   小于等于
        //EQ(equal to)                等于
        //NE(not equal to)            不等于
        //GE(greater than or equal to)大于等于
        //GT(greater than)            大于
        //B(bool) 
        /// 
        private string _operator;
        private string _operatorTip;
        private float _limitFloatValue;
        private bool _limitBoolValue;
        public DataPollLimit(string name, string limitValue, string condition)
            : base(name, true, "", null)
        {
            Condition = condition;
            if (limitValue.Contains("GT"))
            {
                _operator = "GT";
                _operatorTip = ">";
                float.TryParse(limitValue.Replace(_operator, ""), out _limitFloatValue);
            }
            else if (limitValue.Contains("GE"))
            {
                _operator = "GE";
                _operatorTip = ">=";
                float.TryParse(limitValue.Replace(_operator, ""), out _limitFloatValue);
            }
            else if (limitValue.Contains("NE"))
            {
                _operator = "NE";
                _operatorTip = "!=";
                float.TryParse(limitValue.Replace(_operator, ""), out _limitFloatValue);
            }
            else if (limitValue.Contains("EQ"))
            {
                _operator = "EQ";
                _operatorTip = "==";
                float.TryParse(limitValue.Replace(_operator, ""), out _limitFloatValue);
            }
            else if (limitValue.Contains("LE"))
            {
                _operator = "LE";
                _operatorTip = "<=";
                float.TryParse(limitValue.Replace(_operator, ""), out _limitFloatValue);
            }
            else if (limitValue.Contains("LT"))
            {
                _operator = "LT";
                _operatorTip = "<";
                float.TryParse(limitValue.Replace(_operator, ""), out _limitFloatValue);
            }
            else
            {
                _operator = "B";
                _operatorTip = "true";
                _limitBoolValue = limitValue.ToUpper().Contains("ON") ? true : false;
            }
        }
        public override bool CurrentValue
        {
            get
            {
                switch (_operator)
                {
                    case "GT":
                        float.TryParse(DATA.Poll(Name).ToString(), out float valueGT);
                        return valueGT > _limitFloatValue;
                    case "GE":
                        float.TryParse(DATA.Poll(Name).ToString(), out float valueGE);
                        return valueGE >= _limitFloatValue;
                    case "NE":
                        float.TryParse(DATA.Poll(Name).ToString(), out float valueNE);
                        return valueNE != _limitFloatValue;
                    case "EQ":
                        float.TryParse(DATA.Poll(Name).ToString(), out float valueEQ);
                        return valueEQ == _limitFloatValue;
                    case "LE":
                        float.TryParse(DATA.Poll(Name).ToString(), out float valueLE);
                        return valueLE <= _limitFloatValue;
                    case "LT":
                        float.TryParse(DATA.Poll(Name).ToString(), out float valueLT);
                        return valueLT < _limitFloatValue;
                    case "B":
                        bool.TryParse(DATA.Poll(Name).ToString(), out bool valueB);
                        return !(valueB ^ _limitBoolValue);
                    default:
                        return false;
                }
            }
        }
        public override string LimitReason
        {
            get
            {
                return $"DATA.Poll-{Name} = [{DATA.Poll(Name)}] not {_operatorTip} {(_operator == "B" ? _limitBoolValue.ToString() : _limitFloatValue.ToString())}";
            }
        }
    }
    public class CustomLimitBase : InterlockLimit
    {
        public CustomLimitBase(string name, bool limitValue, string tip, Dictionary cultureTip) : base(name, limitValue, tip, cultureTip)
        {
        }
        public override bool CurrentValue { get; }
        public override string LimitReason { get; }
    }
}