/*
 * Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

using Framework.Collections;
using Framework.Constants;
using Framework.Database;
using Game.DataStorage;
using Game.Entities;
using Game.Network.Packets;
using System;
using System.Collections.Generic;

namespace Game
{
    public class Quest
    {
        public Quest(SQLFields fields)
        {
            Id = fields.Read<uint>(0);
            Type = (QuestType)fields.Read<byte>(1);
            Level = fields.Read<int>(2);
            PackageID = fields.Read<uint>(3);
            MinLevel = fields.Read<int>(4);
            QuestSortID = fields.Read<short>(5);
            QuestInfoID = fields.Read<ushort>(6);
            SuggestedPlayers = fields.Read<uint>(7);
            NextQuestInChain = fields.Read<uint>(8);
            RewardXPDifficulty = fields.Read<uint>(9);
            RewardXPMultiplier = fields.Read<float>(10);
            RewardMoney = fields.Read<int>(11);
            RewardMoneyDifficulty = fields.Read<uint>(12);
            RewardMoneyMultiplier = fields.Read<float>(13);
            RewardBonusMoney = fields.Read<uint>(14);

            for (int i = 0; i < SharedConst.QuestRewardDisplaySpellCount; ++i)
                RewardDisplaySpell[i] = fields.Read<uint>(15 + i);

            RewardSpell = fields.Read<uint>(18);
            RewardHonor = fields.Read<uint>(19);
            RewardKillHonor = fields.Read<uint>(20);
            SourceItemId = fields.Read<uint>(21);
            RewardArtifactXPDifficulty = fields.Read<uint>(22);
            RewardArtifactXPMultiplier = fields.Read<float>(23);
            RewardArtifactCategoryID = fields.Read<uint>(24);
            Flags = (QuestFlags)fields.Read<uint>(25);
            FlagsEx = (QuestFlagsEx)fields.Read<uint>(26);

            for (int i = 0; i < SharedConst.QuestItemDropCount; ++i)
            {
                RewardItemId[i] = fields.Read<uint>(27 + i * 4);
                RewardItemCount[i] = fields.Read<uint>(28 + i * 4);
                ItemDrop[i] = fields.Read<uint>(29 + i * 4);
                ItemDropQuantity[i] = fields.Read<uint>(30 + i * 4);

                if (RewardItemId[i] != 0)
                    ++_rewItemsCount;
            }

            for (int i = 0; i < SharedConst.QuestRewardChoicesCount; ++i)
            {
                RewardChoiceItemId[i] = fields.Read<uint>(43 + i * 3);
                RewardChoiceItemCount[i] = fields.Read<uint>(44 + i * 3);
                RewardChoiceItemDisplayId[i] = fields.Read<uint>(45 + i * 3);

                if (RewardChoiceItemId[i] != 0)
                    ++_rewChoiceItemsCount;
            }

            POIContinent = fields.Read<uint>(61);
            POIx = fields.Read<float>(62);
            POIy = fields.Read<float>(63);
            POIPriority = fields.Read<uint>(64);

            RewardTitleId = fields.Read<uint>(65);
            RewardArenaPoints = fields.Read<int>(66);
            RewardSkillId = fields.Read<uint>(67);
            RewardSkillPoints = fields.Read<uint>(68);

            QuestGiverPortrait = fields.Read<uint>(69);
            QuestTurnInPortrait = fields.Read<uint>(70);

            for (int i = 0; i < SharedConst.QuestRewardReputationsCount; ++i)
            {
                RewardFactionId[i] = fields.Read<uint>(71 + i * 4);
                RewardFactionValue[i] = fields.Read<int>(72 + i * 4);
                RewardFactionOverride[i] = fields.Read<int>(73 + i * 4);
                RewardFactionCapIn[i] = fields.Read<uint>(74 + i * 4);
            }

            RewardReputationMask = fields.Read<uint>(91);

            for (int i = 0; i < SharedConst.QuestRewardCurrencyCount; ++i)
            {
                RewardCurrencyId[i] = fields.Read<uint>(92 + i * 2);
                RewardCurrencyCount[i] = fields.Read<uint>(93 + i * 2);

                if (RewardCurrencyId[i] != 0)
                    ++_rewCurrencyCount;
            }

            SoundAccept = fields.Read<uint>(100);
            SoundTurnIn = fields.Read<uint>(101);
            AreaGroupID = fields.Read<uint>(102);
            LimitTime = fields.Read<uint>(103);
            AllowableRaces = fields.Read<int>(104);
            QuestRewardID = fields.Read<uint>(105);
            Expansion = fields.Read<int>(106);

            LogTitle = fields.Read<string>(107);
            LogDescription = fields.Read<string>(108);
            QuestDescription = fields.Read<string>(109);
            AreaDescription = fields.Read<string>(110);
            PortraitGiverText = fields.Read<string>(111);
            PortraitGiverName = fields.Read<string>(112);
            PortraitTurnInText = fields.Read<string>(113);
            PortraitTurnInName = fields.Read<string>(114);
            QuestCompletionLog = fields.Read<string>(115);
        }

        public void LoadQuestDetails(SQLFields fields)
        {
            for (int i = 0; i < SharedConst.QuestEmoteCount; ++i)
            {
                ushort emoteId = fields.Read<ushort>(1 + i);
                if (!CliDB.EmotesStorage.ContainsKey(emoteId))
                {
                    Log.outError(LogFilter.Sql, "Table `quest_details` has non-existing Emote{0} ({1}) set for quest {2}. Skipped.", 1 + i, emoteId, fields.Read<uint>(0));
                    continue;
                }
                DetailsEmote[i] = emoteId;
            }

            for (int i = 0; i < SharedConst.QuestEmoteCount; ++i)
                DetailsEmoteDelay[i] = fields.Read<uint>(5 + i);
        }

        public void LoadQuestRequestItems(SQLFields fields)
        {
            EmoteOnComplete = fields.Read<ushort>(1);
            EmoteOnIncomplete = fields.Read<ushort>(2);

            if (!CliDB.EmotesStorage.ContainsKey(EmoteOnComplete))
                Log.outError(LogFilter.Sql, "Table `quest_request_items` has non-existing EmoteOnComplete ({0}) set for quest {1}.", EmoteOnComplete, fields.Read<uint>(0));

            if (!CliDB.EmotesStorage.ContainsKey(EmoteOnIncomplete))
                Log.outError(LogFilter.Sql, "Table `quest_request_items` has non-existing EmoteOnIncomplete ({0}) set for quest {1}.", EmoteOnIncomplete, fields.Read<uint>(0));

            EmoteOnCompleteDelay = fields.Read<uint>(3);
            EmoteOnIncompleteDelay = fields.Read<uint>(4);
            RequestItemsText = fields.Read<string>(5);
        }

        public void LoadQuestOfferReward(SQLFields fields)
        {
            for (int i = 0; i < SharedConst.QuestEmoteCount; ++i)
            {
                ushort emoteId = fields.Read<ushort>(1 + i);
                if (!CliDB.EmotesStorage.ContainsKey(emoteId))
                {
                    Log.outError(LogFilter.Sql, "Table `quest_offer_reward` has non-existing Emote{0} ({1}) set for quest {2}. Skipped.", 1 + i, emoteId, fields.Read<uint>(0));
                    continue;
                }
                OfferRewardEmote[i] = emoteId;
            }

            for (int i = 0; i < SharedConst.QuestEmoteCount; ++i)
                OfferRewardEmoteDelay[i] = fields.Read<uint>(5 + i);

            OfferRewardText = fields.Read<string>(9);
        }

        public void LoadQuestTemplateAddon(SQLFields fields)
        {
            MaxLevel = fields.Read<byte>(1);
            AllowableClasses = fields.Read<uint>(2);
            SourceSpellID = fields.Read<uint>(3);
            PrevQuestId = fields.Read<int>(4);
            NextQuestId = fields.Read<int>(5);
            ExclusiveGroup = fields.Read<int>(6);
            RewardMailTemplateId = fields.Read<uint>(7);
            RewardMailDelay = fields.Read<uint>(8);
            RequiredSkillId = fields.Read<ushort>(9);
            RequiredSkillPoints = fields.Read<ushort>(10);
            RequiredMinRepFaction = fields.Read<ushort>(11);
            RequiredMaxRepFaction = fields.Read<ushort>(12);
            RequiredMinRepValue = fields.Read<int>(13);
            RequiredMaxRepValue = fields.Read<int>(14);
            SourceItemIdCount = fields.Read<byte>(15);
            RewardMailSenderEntry = fields.Read<uint>(16);
            SpecialFlags = (QuestSpecialFlags)fields.Read<byte>(17);

            if (SpecialFlags.HasAnyFlag(QuestSpecialFlags.AutoAccept))
                Flags |= QuestFlags.AutoAccept;
        }

        public void LoadQuestObjective(SQLFields fields)
        {
            QuestObjective obj = new QuestObjective();
            obj.ID = fields.Read<uint>(0);
            obj.QuestID = fields.Read<uint>(1);
            obj.Type = (QuestObjectiveType)fields.Read<byte>(2);
            obj.StorageIndex = fields.Read<sbyte>(3);
            obj.ObjectID = fields.Read<int>(4);
            obj.Amount = fields.Read<int>(5);
            obj.Flags = (QuestObjectiveFlags)fields.Read<uint>(6);
            obj.Flags2 = fields.Read<uint>(7);
            obj.ProgressBarWeight = fields.Read<float>(8);
            obj.Description = fields.Read<string>(9);

            Objectives.Add(obj);
        }

        public void LoadQuestObjectiveVisualEffect(SQLFields fields)
        {
            uint objID = fields.Read<uint>(1);

            foreach (QuestObjective obj in Objectives)
            {
                if (obj.ID == objID)
                {
                    byte effectIndex = fields.Read<byte>(3);
                    if (obj.VisualEffects == null)
                        obj.VisualEffects = new int[effectIndex + 1];

                    if (effectIndex >= obj.VisualEffects.Length)
                        Array.Resize(ref obj.VisualEffects, effectIndex + 1);

                    obj.VisualEffects[effectIndex] = fields.Read<int>(4);
                    break;
                }
            }
        }

        public uint XPValue(uint playerLevel)
        {
            if (playerLevel != 0)
            {
                uint questLevel = (Level == -1 ? playerLevel : (uint)Level);
                QuestXPRecord questXp = CliDB.QuestXPStorage.LookupByKey(questLevel);
                if (questXp == null || RewardXPDifficulty >= 10)
                    return 0;

                float multiplier = 1.0f;
                if (questLevel != playerLevel)
                    multiplier = CliDB.XpGameTable.GetRow(Math.Min(playerLevel, questLevel)).Divisor / CliDB.XpGameTable.GetRow(playerLevel).Divisor;

                int diffFactor = (int)(2 * (questLevel - playerLevel) + 20);
                if (diffFactor < 1)
                    diffFactor = 1;
                else if (diffFactor > 10)
                    diffFactor = 10;

                uint xp = (uint)(diffFactor * questXp.Exp[RewardXPDifficulty] * RewardXPMultiplier / 10 * multiplier);
                if (xp <= 100)
                    xp = 5 * ((xp + 2) / 5);
                else if (xp <= 500)
                    xp = 10 * ((xp + 5) / 10);
                else if (xp <= 1000)
                    xp = 25 * ((xp + 12) / 25);
                else
                    xp = 50 * ((xp + 25) / 50);

                return xp;
            }

            return 0;
        }

        public uint MoneyValue(uint playerLevel)
        {
            uint level = Level == -1 ? playerLevel : (uint)Level;

            QuestMoneyRewardRecord money = CliDB.QuestMoneyRewardStorage.LookupByKey(level);
            if (money != null)
                return (uint)(money.Money[RewardMoneyDifficulty] * RewardMoneyMultiplier);
            else
                return 0;
        }

        public void BuildQuestRewards(QuestRewards rewards, Player player)
        {
            rewards.ChoiceItemCount = GetRewChoiceItemsCount();
            rewards.ItemCount = GetRewItemsCount();
            rewards.Money = player.GetQuestMoneyReward(this);
            rewards.XP = player.GetQuestXPReward(this);
            rewards.ArtifactCategoryID = RewardArtifactCategoryID;
            rewards.Title = RewardTitleId;
            rewards.FactionFlags = RewardReputationMask;
            for (int i = 0; i < SharedConst.QuestRewardDisplaySpellCount; ++i)
                rewards.SpellCompletionDisplayID[i] = (int)RewardDisplaySpell[i];

            rewards.SpellCompletionID = RewardSpell;
            rewards.SkillLineID = RewardSkillId;
            rewards.NumSkillUps = RewardSkillPoints;
            rewards.RewardID = QuestRewardID;

            for (int i = 0; i < SharedConst.QuestRewardChoicesCount; ++i)
            {
                rewards.ChoiceItems[i].ItemID = RewardChoiceItemId[i];
                rewards.ChoiceItems[i].Quantity = RewardChoiceItemCount[i];
            }

            for (int i = 0; i < SharedConst.QuestRewardItemCount; ++i)
            {
                rewards.ItemID[i] = RewardItemId[i];
                rewards.ItemQty[i] = RewardItemCount[i];
            }

            for (int i = 0; i < SharedConst.QuestRewardReputationsCount; ++i)
            {
                rewards.FactionID[i] = RewardFactionId[i];
                rewards.FactionOverride[i] = RewardFactionOverride[i];
                rewards.FactionValue[i] = RewardFactionValue[i];
                rewards.FactionCapIn[i] = (int)RewardFactionCapIn[i];
            }

            for (int i = 0; i < SharedConst.QuestRewardCurrencyCount; ++i)
            {
                rewards.CurrencyID[i] = RewardCurrencyId[i];
                rewards.CurrencyQty[i] = RewardCurrencyCount[i];
            }
        }

        public uint GetRewMoneyMaxLevel()
        {
            // If Quest has flag to not give money on max level, it's 0
            if (HasFlag(QuestFlags.NoMoneyFromXp))
                return 0;

            // Else, return the rewarded copper sum modified by the rate
            return (uint)(RewardBonusMoney * WorldConfig.GetFloatValue(WorldCfg.RateMoneyMaxLevelQuest));
        }

        public bool IsAutoAccept()
        {
            return !WorldConfig.GetBoolValue(WorldCfg.QuestIgnoreAutoAccept) && HasFlag(QuestFlags.AutoAccept);
        }

        public bool IsAutoComplete()
        {
            return !WorldConfig.GetBoolValue(WorldCfg.QuestIgnoreAutoComplete) && Type == QuestType.AutoComplete;
        }

        public bool IsRaidQuest(Difficulty difficulty)
        {
            switch ((QuestInfos)QuestInfoID)
            {
                case QuestInfos.Raid:
                    return true;
                case QuestInfos.Raid10:
                    return difficulty == Difficulty.Raid10N || difficulty == Difficulty.Raid10HC;
                case QuestInfos.Raid25:
                    return difficulty == Difficulty.Raid25N || difficulty == Difficulty.Raid25HC;
                default:
                    break;
            }

            if (Flags.HasAnyFlag(QuestFlags.Raid))
                return true;

            return false;
        }

        public bool IsAllowedInRaid(Difficulty difficulty)
        {
            if (IsRaidQuest(difficulty))
                return true;

            return WorldConfig.GetBoolValue(WorldCfg.QuestIgnoreRaid);
        }

        public uint CalculateHonorGain(uint level)
        {
            uint honor = 0;
            return honor;
        }

        public bool CanIncreaseRewardedQuestCounters()
        {
            // Dungeon Finder/Daily/Repeatable (if not weekly, monthly or seasonal) quests are never considered rewarded serverside.
            // This affects counters and client requests for completed quests.
            return (!IsDFQuest() && !IsDaily() && (!IsRepeatable() || IsWeekly() || IsMonthly() || IsSeasonal()));
        }

        public bool HasFlag(QuestFlags flag) { return (Flags & flag) != 0; }

        public void SetFlag(QuestFlags flag) { Flags |= flag; }

        public bool HasSpecialFlag(QuestSpecialFlags flag) { return (SpecialFlags & flag) != 0; }

        public void SetSpecialFlag(QuestSpecialFlags flag) { SpecialFlags |= flag; }

        // table data accessors:
        public bool IsRepeatable() { return SpecialFlags.HasAnyFlag(QuestSpecialFlags.Repeatable); }
        public bool IsDaily() { return Flags.HasAnyFlag(QuestFlags.Daily); }
        public bool IsWeekly() { return Flags.HasAnyFlag(QuestFlags.Weekly); }
        public bool IsMonthly() { return SpecialFlags.HasAnyFlag(QuestSpecialFlags.Monthly); }
        public bool IsSeasonal()
        {
            return (QuestSortID == -(int)QuestSort.Seasonal || QuestSortID == -(int)QuestSort.Special || QuestSortID == -(int)QuestSort.LunarFestival
                || QuestSortID == -(int)QuestSort.Midsummer || QuestSortID == -(int)QuestSort.Brewfest || QuestSortID == -(int)QuestSort.LoveIsInTheAir
                || QuestSortID == -(int)QuestSort.Noblegarden) && !IsRepeatable();
        }
        public bool IsDailyOrWeekly() { return Flags.HasAnyFlag(QuestFlags.Daily | QuestFlags.Weekly); }
        public bool IsDFQuest() { return SpecialFlags.HasAnyFlag(QuestSpecialFlags.DfQuest); }

        public uint GetRewChoiceItemsCount() { return _rewChoiceItemsCount; }
        public uint GetRewItemsCount() { return _rewItemsCount; }
        public uint GetRewCurrencyCount() { return _rewCurrencyCount; }

        #region Fields
        public uint Id;
        public QuestType Type;
        public int Level;
        public uint PackageID;
        public int MinLevel;
        public int QuestSortID;
        public uint QuestInfoID;
        public uint SuggestedPlayers;
        public uint NextQuestInChain { get; set; }
        public uint RewardXPDifficulty;
        public float RewardXPMultiplier;
        public int RewardMoney;
        public uint RewardMoneyDifficulty;
        public float RewardMoneyMultiplier;
        public uint RewardBonusMoney;
        public uint[] RewardDisplaySpell = new uint[SharedConst.QuestRewardDisplaySpellCount];
        public uint RewardSpell { get; set; }
        public uint RewardHonor;
        public uint RewardKillHonor;
        public uint RewardArtifactXPDifficulty;
        public float RewardArtifactXPMultiplier;
        public uint RewardArtifactCategoryID;
        public uint SourceItemId { get; set; }
        public QuestFlags Flags { get; set; }
        public QuestFlagsEx FlagsEx;
        public uint[] RewardItemId = new uint[SharedConst.QuestRewardItemCount];
        public uint[] RewardItemCount = new uint[SharedConst.QuestRewardItemCount];
        public uint[] ItemDrop = new uint[SharedConst.QuestItemDropCount];
        public uint[] ItemDropQuantity = new uint[SharedConst.QuestItemDropCount];
        public uint[] RewardChoiceItemId = new uint[SharedConst.QuestRewardChoicesCount];
        public uint[] RewardChoiceItemCount = new uint[SharedConst.QuestRewardChoicesCount];
        public uint[] RewardChoiceItemDisplayId = new uint[SharedConst.QuestRewardChoicesCount];
        public uint POIContinent;
        public float POIx;
        public float POIy;
        public uint POIPriority;
        public uint RewardTitleId { get; set; }
        public int RewardArenaPoints;
        public uint RewardSkillId;
        public uint RewardSkillPoints;
        public uint QuestGiverPortrait;
        public uint QuestTurnInPortrait;
        public uint[] RewardFactionId = new uint[SharedConst.QuestRewardReputationsCount];
        public int[] RewardFactionValue = new int[SharedConst.QuestRewardReputationsCount];
        public int[] RewardFactionOverride = new int[SharedConst.QuestRewardReputationsCount];
        public uint[] RewardFactionCapIn = new uint[SharedConst.QuestRewardReputationsCount];
        public uint RewardReputationMask;
        public uint[] RewardCurrencyId = new uint[SharedConst.QuestRewardCurrencyCount];
        public uint[] RewardCurrencyCount = new uint[SharedConst.QuestRewardCurrencyCount];
        public uint SoundAccept { get; set; }
        public uint SoundTurnIn { get; set; }
        public uint AreaGroupID;
        public uint LimitTime;
        public int AllowableRaces { get; set; }
        public uint QuestRewardID;
        public int Expansion;
        public List<QuestObjective> Objectives = new List<QuestObjective>();
        public string LogTitle = "";
        public string LogDescription = "";
        public string QuestDescription = "";
        public string AreaDescription = "";
        public string PortraitGiverText = "";
        public string PortraitGiverName = "";
        public string PortraitTurnInText = "";
        public string PortraitTurnInName = "";
        public string QuestCompletionLog = "";

        // quest_detais table
        public uint[] DetailsEmote = new uint[SharedConst.QuestEmoteCount];
        public uint[] DetailsEmoteDelay = new uint[SharedConst.QuestEmoteCount];

        // quest_request_items table
        public uint EmoteOnComplete;
        public uint EmoteOnIncomplete;
        public uint EmoteOnCompleteDelay;
        public uint EmoteOnIncompleteDelay;
        public string RequestItemsText = "";

        // quest_offer_reward table
        public uint[] OfferRewardEmote = new uint[SharedConst.QuestEmoteCount];
        public uint[] OfferRewardEmoteDelay = new uint[SharedConst.QuestEmoteCount];
        public string OfferRewardText = "";

        // quest_template_addon table (custom data)
        public uint MaxLevel;
        public uint AllowableClasses { get; set; }
        public uint SourceSpellID { get; set; }
        public int PrevQuestId;
        public int NextQuestId;
        public int ExclusiveGroup;
        public uint RewardMailTemplateId { get; set; }
        public uint RewardMailDelay { get; set; }
        public uint RequiredSkillId;
        public uint RequiredSkillPoints;
        public uint RequiredMinRepFaction;
        public int RequiredMinRepValue;
        public uint RequiredMaxRepFaction;
        public int RequiredMaxRepValue;
        public uint SourceItemIdCount;
        public uint RewardMailSenderEntry;
        public QuestSpecialFlags SpecialFlags; // custom flags, not sniffed/WDB

        public List<int> prevQuests = new List<int>();
        public List<uint> prevChainQuests = new List<uint>();

        uint _rewChoiceItemsCount;
        uint _rewItemsCount;
        uint _rewCurrencyCount;
        #endregion
    }

    public class QuestStatusData
    {
        public QuestStatus Status;
        public uint Timer;
        public int[] ObjectiveData;
    }

    public class QuestTemplateLocale
    {
        public StringArray LogTitle = new StringArray((int)LocaleConstant.Total);
        public StringArray LogDescription = new StringArray((int)LocaleConstant.Total);
        public StringArray QuestDescription = new StringArray((int)LocaleConstant.Total);
        public StringArray AreaDescription = new StringArray((int)LocaleConstant.Total);
        public StringArray PortraitGiverText = new StringArray((int)LocaleConstant.Total);
        public StringArray PortraitGiverName = new StringArray((int)LocaleConstant.Total);
        public StringArray PortraitTurnInText = new StringArray((int)LocaleConstant.Total);
        public StringArray PortraitTurnInName = new StringArray((int)LocaleConstant.Total);
        public StringArray QuestCompletionLog = new StringArray((int)LocaleConstant.Total);
    }

    public class QuestRequestItemsLocale
    {
        public StringArray CompletionText = new StringArray((int)LocaleConstant.Total);
    }

    public class QuestObjectivesLocale
    {
        public StringArray Description = new StringArray((int)LocaleConstant.Total);
    }

    public class QuestOfferRewardLocale
    {
        public StringArray RewardText = new StringArray((int)LocaleConstant.Total);
    }

    public class QuestObjective
    {
        public uint ID;
        public uint QuestID;
        public QuestObjectiveType Type;
        public sbyte StorageIndex;
        public int ObjectID;
        public int Amount;
        public QuestObjectiveFlags Flags;
        public uint Flags2;
        public float ProgressBarWeight;
        public string Description;
        public int[] VisualEffects = new int[0];

        public bool IsStoringFlag()
        {
            switch (Type)
            {
                case QuestObjectiveType.AreaTrigger:
                case QuestObjectiveType.WinPetBattleAgainstNpc:
                case QuestObjectiveType.DefeatBattlePet:
                case QuestObjectiveType.CriteriaTree:
                    return true;
                default:
                    break;
            }
            return false;
        }
    }
}
