using Earthblend.Nts.Common;
using Earthblend.Tts.Common.Core.Enumerations;
using Earthblend.Tts.Common.Core.Extentions;
using Earthblend.Tts.Common.Core.Statics;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows.Input;
using System.Windows.Media.Media3D;
using System.Xml.Serialization;

namespace Earthblend.Tts.Common.Core.Members
{
    public class Node : CustomBindableBase
    {
        public Node() { }

        private int _sequence = 0;

        private Boolean _isRoot = false;
        private Node _searchPlanRoot = null;
        private long _candidates = 0;
        private Double _max = 0;
        private ObservableCollection<Permutation> _permutationResults = new ObservableCollection<Permutation>();
        private Node _worldTargets = null;
        private Model3DGroup _worldModel3DGroup = null;
        private ObservableCollection<PermutationRule> _permutationRules = new ObservableCollection<PermutationRule>();

        public Node SearchPlanRoot { get { return _searchPlanRoot; } set { if (_searchPlanRoot == value) return; SetProperty(ref _searchPlanRoot, value); } }


        private ObservableCollection<Symbol> _symbolCollection = new ObservableCollection<Symbol>();

        public ObservableCollection<Symbol> SymbolCollection { get { return _symbolCollection; } set { if (_symbolCollection == value) return; SetProperty(ref _symbolCollection, value); } }
        public ObservableCollection<PermutationRule> PermutationRules { get { return _permutationRules; } set { if (_permutationRules == value) return; SetProperty(ref _permutationRules, value); } }

        [XmlIgnore] Dictionary<Char, String> codes = new Dictionary<Char, String>();
        public Boolean IsRoot { get { return _isRoot; } set { if (_isRoot == value) return; SetProperty(ref _isRoot, value); } }
        public int Sequence { get { return _sequence; } set { if (_sequence == value) return; SetProperty(ref _sequence, value); } }

        private Boolean HasCode(String possibleCode)
        {
            foreach (char c in possibleCode)
            {
                if (codes.ContainsKey(c)) return true;
            }

            return false;
        }

        private Boolean HasRuleChar(String ruleValue)
        {
            foreach (char c in Text)
            {
                if (codes.ContainsKey(c)) return true;
            }

            return false;
        }

        [XmlIgnore]
        public IEnumerable<PermutationRule> FilteredPermutationRules
        {
            get
            {
                //A#C~@
                if (!codes.Any())
                {
                    codes.Add('A', "Alphabet");
                    codes.Add('#', "Number");
                    codes.Add('C', "Constant");
                    codes.Add('~', "Superscript");
                    codes.Add('@', "Subscript");
                }

                //Add more conditions for green
                foreach (var permutationRule in PermutationRules)
                {
                    //if (permutationRule.Value == "A)") { }

                    permutationRule.Color = "Red";

                    if (HasCode(permutationRule.Value))
                    {
                        Dictionary<int, Boolean> passed = new Dictionary<int, Boolean>();
                        for (int i = 1; i <= permutationRule.Value.Length; i++) passed.Add(i, false);

                        int index = 0;
                        foreach (Char c in permutationRule.Value)
                        {
                            index++;

                            switch (c)
                            {
                                case 'A':
                                    foreach (var t in Text)
                                    {
                                        if (VariableUtil.AlphabetChar.ContainsKey(t))
                                        {
                                            passed[index] = true;
                                            break;
                                        }
                                    }
                                    break;
                                case '#':
                                    foreach (var t in Text)
                                    {
                                        if (t.IsNumeric())
                                        {
                                            passed[index] = true;
                                            break;
                                        }
                                    }
                                    break;
                                case 'C':
                                    foreach (var t in Text)
                                    {
                                        if (VariableUtil.ConstantChar.ContainsKey(t))
                                        {
                                            passed[index] = true;
                                            break;
                                        }
                                    }
                                    break;
                                case '~':
                                    foreach (var t in Text)
                                    {
                                        if (VariableUtil.KnownSuperscriptsTableChar.ContainsKey(t))
                                        {
                                            passed[index] = true;
                                            break;
                                        }
                                    }
                                    break;
                                case '@':
                                    foreach (var t in Text)
                                    {
                                        if (VariableUtil.KnownSubscriptsTableChar.ContainsKey(t))
                                        {
                                            passed[index] = true;
                                            break;
                                        }
                                    }
                                    break;
                                default:
                                    if (Text.Contains(c))
                                    {
                                        passed[index] = true;
                                        break;
                                    }
                                    break;
                            }
                        }

                        if (!passed.ContainsValue(false)) permutationRule.Color = "Green";

                    }
                    else
                    {
                        switch (permutationRule.Comparision)
                        {
                            case "StartsWithSubscript":
                                if (VariableUtil.KnownSuperscriptsTableChar.ContainsKey(Text[0]))
                                    permutationRule.Color = "Green";
                                break;
                            case "FirstParanIsRight":
                                if (Text.Contains(")"))
                                    permutationRule.Color = "Green";
                                break;
                            case "EndsWithOperator":
                                if (VariableUtil.KnownOperators.Contains(Text.Substring(Text.Length - 1, 1)))
                                    permutationRule.Color = "Green";
                                break;
                            default:
                                if (!String.IsNullOrEmpty(permutationRule.Value)) if (Text.Contains(permutationRule.Value)) permutationRule.Color = "Green";
                                break;
                        }
                    }
                }

                var predicate = PredicateBuilder.True<PermutationRule>();

                return (PermutationRules.AsQueryable()).Where(predicate.Compile()).OrderBy(c => c.Color).ToList();
            }
        }

        public Node(String text)
        {
            this._text = text;
        }

        public long Candidates { get { return _candidates; } set { if (_candidates == value) return; SetProperty(ref _candidates, value); } }

        public Double Max { get { return _max; } set { if (_max == value) return; SetProperty(ref _max, value); } }

        public ObservableCollection<Permutation> PermutationResults { get { return _permutationResults; } set { if (_permutationResults == value) return; SetProperty(ref _permutationResults, value); } }

        public Node WorldTargets { get { return _worldTargets; } set { if (_worldTargets == value) return; SetProperty(ref _worldTargets, value); } }

        [XmlIgnore] public Model3DGroup WorldModel3DGroup { get { return _worldModel3DGroup; } set { if (_worldModel3DGroup == value) return; SetProperty(ref _worldModel3DGroup, value); } }


        public void SortChildNodes()
        {
            var nodes = ChildNodes.OrderBy(c => c.Sequence);
            ChildNodes = nodes.ToObservableCollection();
        }

        private ObservableCollection<Node> childNodes = null;

        public ObservableCollection<Node> ChildNodes
        {
            get
            {
                if (this.childNodes == null) this.childNodes = new ObservableCollection<Node>();

                return this.childNodes;//.OrderBy(c=>c.Sequence).ToObservableCollection();
            }
            set
            {
                if (childNodes == value) return;
                SetProperty(ref childNodes, value);
            }
        }

        private ICommand _command = null;
        private Object _commandParameter = null;

        private String _text = String.Empty;
        private String _sourceCode = String.Empty;
        private String _path = String.Empty;
        private Guid _parentId = Guid.Empty;
        private Boolean _isExpanded = true;
        private Boolean _isSelected = false;
        private Boolean _isActiveTarget = false;
        private Boolean _isInvalid = false;
        private NodeType _treeNodeType = NodeType.SlateCategory;

        public NodeType TreeNodeType { get { return _treeNodeType; } set { if (_treeNodeType == value) return; SetProperty(ref _treeNodeType, value); } }

        [XmlIgnore] public ICommand Command { get { return _command; } set { if (_command == value) return; SetProperty(ref _command, value); } }
        [XmlIgnore] public Object CommandParameter { get { return _commandParameter; } set { if (_commandParameter == value) return; SetProperty(ref _commandParameter, value); } }

        [XmlIgnore] public String SourceCode { get { return _sourceCode; } set { if (_sourceCode == value) return; SetProperty(ref _sourceCode, value); } }


        public String Text { get { return _text; } set { if (_text == value) return; SetProperty(ref _text, value); } }
        public String Path { get { return _path; } set { if (_path == value) return; SetProperty(ref _path, value); } }
        public Guid ParentId { get { return _parentId; } set { if (_parentId == value) return; SetProperty(ref _parentId, value); } }
        public Boolean IsExpanded { get { return _isExpanded; } set { if (_isExpanded == value) return; SetProperty(ref _isExpanded, value); } }
        public Boolean IsSelected { get { return _isSelected; } set { if (_isSelected == value) return; SetProperty(ref _isSelected, value); } }
        public Boolean IsActiveTarget { get { return _isActiveTarget; } set { if (_isActiveTarget == value) return; SetProperty(ref _isActiveTarget, value); } }
        public Boolean IsInvalid { get { return _isInvalid; } set { if (_isInvalid == value) return; SetProperty(ref _isInvalid, value); } }

        private ObservableCollection<Term> _terms = new ObservableCollection<Term>();

        public ObservableCollection<Term> Terms { get { return _terms; } set { if (_terms == value) return; SetProperty(ref _terms, value); } }
    }
}