import { eqi18n, eqconsts, Query, DataModel, EqContext } from '@easyquery/core' 

export function registerQueryPanelWidget($) {

    $.widget("eqjs.QueryPanel", {
        _activeConditionWidget: null,
        _rootPredicateWidget: null,
        _query: null,
        _context: null,

        _globalCondCounter: 0,
        _globalPredCounter: 0,

        _defaultMenuOptions: {
            showSearchBoxAfter: 30,
            searchBoxAutoFocus: true,
            activateOnMouseOver: true
        },

        _queryObserverId: null,
        options: {
            isSubQuery: false,
            activeCondition: null,

            listRequestHandler: null, //deprecated
            entitiesPopupHandler: null,
            entitiesListFilter: null,
            menuContainer: document.body,

            /// <option name="showRootRow" type="Boolean" default="true">
            /// <summary>Gets or sets a value indicating whether query panel must show a root row which represents the main group of conditions</summary>
            /// </option>
            showRootRow: true,

            /// <option name="showAddRow" type="Boolean" default="true">
            /// <summary>Gets or sets a value indicating whether query panel must show a special [add condition] link at the bottom</summary>
            /// </option>
            showAddRow: true,


            /// <option name="showCheckboxes" type="Boolean" default="false">
            /// <summary>Gets or sets a value indicating whether query panel must show a checkbox at the beginning of each condition row. 
            /// User will be able to use these checkboxes to enable/disable corresponding query conditions
            /// </summary>
            /// </option>
            showCheckboxes: false,


            /// <option name="allowParameterization" type="Boolean" default="false">
            /// <summary>Gets or sets a value indicating whether query panel shows "toggle parameterization" button which aloows to mark each condition as parameterized. 
            /// </summary>
            /// </option>
            allowParameterization: false,

            /// <option name="allowInJoinConditions" type="Boolean" default="false">
            /// <summary>Gets or sets a value indicating whether query panel allows to place some conditions in to JOIN clause instead of WHERE. 
            /// </summary>
            /// </option>
            allowInJoinConditions: false,

            /// <option name="showPoweredBy" type="Boolean" default="true">
            /// <summary>Allows to turn off "Powered by EasyQuery" link shown in the bottom right cornder of query panel. Works only in the full version of the script.</summary>
            /// </option>
            showPoweredBy: true,

            /// <option name="buttons" type="Object">
            /// <summary>
            /// Defines which buttons should be shown in the condition/predicate when the mouse is over. 
            /// Possible values are:
            /// - "addCondition" - the button that allows to add new condition. Is shown in predicates only.
            /// - "addPredicate" - the button that allows to add new predicate. Is shown in predicates only.
            /// - "enable" - the button that allows to enable or disable certain condition.
            /// - "delete" - the button that allows to delete certain condition.
            /// - "menu" - the button that shows menu with all available actions for the condition/predicate, including the actions that are not available using other buttons. 
            /// By default the option is not set, it actually means 
            /// {
            ///   condition: ["enable", "delete"]
            ///   predicate: ["addCondition", "addPredicate", "enable", "delete"]
            /// }
            /// </summary>
            /// <prop name="condition" type="Array(String)" default="null">
            /// An array of strings that defines which buttons should be shown in conditions. 
            /// </prop> 
            /// <prop name="predicate" type="Array(String)" default="null">
            /// An array of strings that defines which buttons should be shown in predicates. 
            /// </prop> 
            /// </option>
            buttons: {
                condition: null,
                predicate: null
            },

            /// <option name="alwaysShowButtonsInPredicates" type="Boolean" default="false">
            /// <summary>
            /// If true QueryPanel widget will always show button in predicate (group) rows.
            /// Instead of default behaviour when they are shown only on mouse over.
            /// </summary>
            /// </option>
            alwaysShowButtonsInPredicates: false,

            /// <option name="alwaysShowButtonsInConditions" type="Boolean" default="false">
            /// <summary>
            /// If true QueryPanel widget will always show button in condition rows.
            /// Instead of default behaviour when they are shown only on mouse over.
            /// </summary>
            /// </option>
            alwaysShowButtonsInConditions: false,

            /// <option name="showConjunctions" type="Boolean" default="true">
            /// <summary>
            /// If true QueryPanel widget will show conjunction elements ("and" or "or") at the beginning of each condition.
            /// </summary>
            /// </option>
            showConjunctions: true,

            /// <option name="accentActiveCondition" type="Boolean" default="true">
            /// <summary>
            /// If true the active condition (the one user clicked on previously) will have accent background color.
            /// </summary>
            /// </option>
            accentActiveCondition: true,

            /// <option name="activateRootOnStart" type="Boolean" default="true">
            /// <summary>
            /// If true root predicate row become active at the beginning.
            /// </summary>
            /// </option>
            activateRootOnStart: true,

            /// <option name="dateFormatValue" type="String" default="">
            /// <summary>
            /// A string that represents the format of date values used in date/time picker widget. 
            /// For a full list of the possible formats see documention for JQuery UI Datepicker Widget: http://api.jqueryui.com/datepicker/#utility-formatDate 
            /// </summary>
            /// </option>
            dateFormatValue: '', //'mm/dd/yy',

            /// <option name="dateFormatDisplay" type="String" default="d MM, yy">
            /// <summary>
            /// The format of date values used in condition rows.
            /// For a full list of the possible formats see documention for JQuery UI Datepicker Widget: http://api.jqueryui.com/datepicker/#utility-formatDate 
            /// </summary>
            /// </option>
            //dateFormatDisplay: undefined,

            /// <option name="yearRange" type="String" default="c-10:c+10">
            /// <summary>
            /// The range of years displayed in the year drop-down: either relative to today's year ("-nn:+nn"), relative to the currently selected year ("c-nn:c+nn"), absolute ("nnnn:nnnn"), or combinations of these formats ("nnnn:-nn"). 
            /// </summary>
            /// </option>
            yearRange: 'c-10:c+10',

            /// <option name="attrElementFormat" type="String" default="{entity} {attr}">
            /// <summary>
            /// The format of entity attributes used in query panel conditions.
            /// You can set it to '{attr}' to shown only attribute part (without entity name)
            /// </summary>
            /// </option>
            attrElementFormat: '{entity} {attr}',

            /// <option name="menuOptions" type="Object">
            /// <summary>
            /// Contains different options for popup menu that appears for selecting attributes, operators or values in condition.\\
            /// Includes the following sub-options:
            /// </summary>
            /// <prop name="showSearchBoxAfter" type="integer" default="30">
            /// If the number of items in drop down menu exceeds this number then a search box will be displayed. 
            /// Set this option to 0 if want to show the search box in any case
            /// </prop> 
            /// <prop name="searchBoxAutoFocus" type="boolean" default="true">
            /// If true  - the SearchBox gets focus automatically when the menu level is shown.
            /// </prop>
            /// <prop name="activateOnMouseOver" type="boolean" default="true">
            /// If true  - the row in query panel will be highlighted when user moves mouse cursor over it.
            /// </prop> 
            /// <prop name="itemRenderedCallback" type="function" default="null">
            /// The callback that is called when the menu item has been rendered. It allows you to make any changes you need to the markup of the menu item.
            /// Parameters:
            ///     menuId - the ID of the menu
            ///     itemDiv - jQuery object that represents the menu item div
            /// For example, if you need to add some class:
            /// <code>
            /// itemRenderedCallbackHandler: function (menuId, itemDiv) {
            ///    itemDiv.addClass("some-cool-class");
            /// }
            /// </code>
            /// </prop>
            /// </option>
            menuOptions: {
                showSearchBoxAfter: 30,
                searchBoxAutoFocus: true,
                activateOnMouseOver: true,
                itemRenderedCallback: null
            },

            /// <option name="allowDragDrop" type="Boolean" default="true">
            /// <summary>Gets or sets a value indicating whether it's possible to drag attributes from EntitiesPanel and drop them into QueryPanel to create new conditions.</summary>
            /// </option>
            allowDragDrop: true,

            /// <option name="attrPlacement" type="Integer" default="0">
            /// <summary>
            /// Defines where to display attributes in the tree:
            /// 0 - attributes are displayed after entities
            /// 1 - attributes are displayed before entities
            /// 2 - attributes and entities are mixed, and displayed in alphabetical order. In this case the "sortEntities" option value dosn't matter.
            /// </summary>
            /// </option>
            attrPlacement: 0,

            /// <option name="sortEntities" type="Integer" default="false">
            /// <summary>
            /// Defines whether entities and attributes should be sorted alphabetically. If false, they are displayed as listed in the model.
            /// </summary>
            /// </option>
            sortEntities: false,

            /// <option type="Integer" default="600">
            /// <summary>
            /// Sets or gets the width of sub-query dialog
            /// </summary>
            /// </option>
            subQueryDialogWidth: 600,

            /// <option type="Integer" default="300">
            /// <summary>
            /// Sets or gets the height of sub-query dialog
            /// </summary>
            /// </option>
            subQueryDialogHeight: 300,


            /// <option type="Integer" default="100000">
            /// <summary>
            /// Sets or gets the ZIndex property of the different dialogs used in QueryPanel (including the sub-query dialog)
            /// </summary>
            /// </option>
            dialogZIndex: 100000,

            /// <option type="String" default=".">
            /// <summary>
            /// Sets or gets the symbol which is used as decimal separator
            /// </summary>
            /// </option>
            //numberDecimalSeparatorDisplay: '',

            /// <option type="List" default="[',', ';']">
            /// <summary>
            /// Sets or gets the symbols which are recognized as list items separators 
            /// (for example when user is supposed to enter a list of values in a text box).
            /// </summary>
            /// </option>
            numberListSeparators: [',', ';'],

            /// <option type="Boolean" default="false">
            /// <summary>
            /// If true the QueryPanel will automaticall show value editor for any new (just added) condition.
            /// </summary>
            /// </option>
            autoEditNewCondition: false,

            /// <option name="conditionRenderedCallback" type="function" default="null">
            /// <summary>
            /// The callback that is called when the condition's row has been rendered. It allows you to make any changes you need to the markup of the row.
            /// Parameters:
            ///     condDiv - jQuery object that represents the condition's row div
            /// For example, if you need to add some class:
            /// <code>
            /// conditionRenderedCallbackHandler: function (condDiv) {
            ///    condDiv.addClass("some-cool-class");
            /// }
            /// </code>
            /// </summary>
            /// </option>
            conditionRenderedCallback: null,

            /// <option name="predicateRenderedCallback" type="function" default="null">
            /// <summary>
            /// The callback that is called when the predicate's row has been rendered. It allows you to make any changes you need to the markup of the row.
            /// Parameters:
            ///     predDiv - jQuery object that represents the predicate's row div
            /// For example, if you need to add some class:
            /// <code>
            /// predicateRenderedCallbackHandler: function (predDiv) {
            ///    predDiv.addClass("some-cool-class");
            /// }
            /// </code>
            /// </summary>
            /// </option>
            predicateRenderedCallback: null
        },

        addRowHeight: 0,

        getSelf: function () {
            return this;
        },

        getQuery: function() {
            return this._query;
        },

        setQuery: function (query) {
            this._setQueryObserver(true); //removing old query observer
            this._query = query;

            if (query) {
                this._setQueryObserver();
                this.refresh();
            }
        },

        setContext: function(context: EqContext) {
            this._context = context;
        },

        getContext: function() {
            return this._context;
        },

        isQueryNullOrEmpty: function() {
            var query = this.getQuery();
            return !query || query.isEmptyConditions();
        },

        getModel: function (): DataModel {
            var query: Query = this.getQuery();
            return query ? query.getModel() : null;
        },

        isModelNullOrEmpty: function() {
            var model: DataModel = this.getModel();
            return !model || model.isEmpty();
        },

        _updateLists: function () {
            var constLists = eqconsts.constLists;

            for (var prop in constLists) {
                if (constLists.hasOwnProperty(prop)) {
                    this._updateList(constLists[prop]);
                }
            };

            this._updateList(eqconsts.predicateLinkTypeList);
        },

        _updateList: function (list) {
            if (!list) return;
            
            var listLength = list.length;
            for (var i = 0; i < listLength; i++) {
                list[i].text = eqi18n.getText(list[i].key);
                if (!list[i].text)
                    list[i].text = list[i].key;
            }
        },

        _create: function () {
            var self = this;
        },

        _render: function (isRefresh : boolean = false) {
            var self = this;

            let model:DataModel = this.getModel();            

            self._clear(isRefresh);

            self._updateLists();


            self.element.addClass('eqjs-qp-panel');

            if (!self.isModelNullOrEmpty()) {

                self.options.entitiesList = self.getEntitiesList({ addUIC: true, addUIR: false, addUIS: false, attrPlacement: self.options.attrPlacement, sortEntities: self.options.sortEntities });
                self.options.entitiesMenu = self._createEntitiesMenu();
                self.options.rootPredicateMenu = self._createPredicateMenu(true);
                self.options.predicateMenu = self._createPredicateMenu();
                self.options.conditionMenu = self._createConditionMenu();


                //Conditions
                var rootBlock = $('<div></div>');
                if (self.element.attr('id')) {
                    rootBlock.attr('id', self.element.attr('id') + '-pred-root');
                }
                rootBlock.appendTo(self.element);

                //AddRow
                if (self.options.showAddRow) {
                    var addRowBlock = $('<div class="eqjs-addrow eqjs-qp-addrow"></div>');
                    addRowBlock.appendTo(self.element);

                    if (!self.options.showRootRow && (!self.isQueryNullOrEmpty())) {
                        addRowBlock.addClass('eqjs-addrow-empty');
                    }


                    var addRowLink = $('<a href="javascript:void(0)">' + eqi18n.getText('CmdClickToAddCondition') + '</a>');
                    addRowLink.appendTo(addRowBlock);

                    addRowLink.click(function (e) {
                        e.preventDefault();
                        self.showEntitiesMenu({
                            anchor: addRowLink,
                            selectedIds: null,
                            itemSelectedCallback: function (evt, data) {
                                var attrid = data.menuItem.data('id');

                                self.addNewCondition(attrid);
                                return false;
                            }
                        });
                    });

                    self.addRowHeight = addRowBlock.outerHeight();
                }

                self._refreshByQuery(rootBlock);
            }

            if (self.options.allowDragDrop) {
                self.element.droppable({
                    hoverClass: "eqjs-drophover",
                    scope: "entityAttr",

                    drop: function (event, ui) {
                        self.addNewCondition(ui.draggable.data("id"));
                    },
                    over: function (event, ui) {
                        ui.helper.addClass('eqjs-qc-column-drag');

                        var attrId = ui.draggable.data("id");

                        if (!model.checkAttrProperty(attrId, "useInCondition")) {
                            ui.helper.addClass('eqjs-qc-column-drag-forbidden');
                        }
                    },
                    out: function (event, ui) {
                        ui.helper.removeClass('eqjs-qc-column-drag');
                        ui.helper.removeClass('eqjs-qc-column-drag-forbidden');
                    }
                });
            }

        },

		
		_cssPwby: function (pwdbylnk) {
			pwdbylnk.css({
				'color': '#4676AE',
				'font': '11px Calibri',
				'position': 'absolute',
				'top': '-16px',
				'right': '3px'
			});
		},
		
        _updPwby: function () {
            let model = this.getModel();
            let pwby = this.options.showPoweredBy;

            if (this._pwdbylnk) {
                this._pwdbylnk.remove();
            }

            if (pwby || !model || !model.rgdlce()) {

                this._pwdbylnk = $('<a></a>', {
                    'id': "PWDBY",
                    'text': 'Powered by EasyQuery',
                    'href': 'https://korzh.com/easyquery',
                    'target': '_blank'
                }).hide().appendTo(this.element);

                let self = this;

                let placePoweredByLink = function () {
					self._cssPwby(self._pwdbylnk);
                    let isNotInDialog = self._pwdbylnk.parents('div[class*=ui-dialog]').length === 0; 
                    if (isNotInDialog) {
                        self._pwdbylnk.show();
                    }
                };
                placePoweredByLink();
            }
        },


        _checkActivateRootPredicate: function () {
            if (this.options.activateRootOnStart) {
                this._activateRootPredicate();
            }
        },

        _activateRootPredicate: function () {
            if (this.options.showRootRow) { // && this.options.accentActiveCondition && this.options.activateRootOnStart) {
                if (this._rootPredicateWidget) {
                    this.setActiveConditionWidget(this._rootPredicateWidget);
                }
            }
        },

        _setOption: function (key, value) {
            if (arguments.length == 2) {
                if (key == 'model') {
                    this.clearQuery(false);
                    this.options[key] = value;
                    this._render();
                    this._checkActivateRootPredicate();
                }
                else if (key == 'query') {
                    this.setQuery(value);
                }
                else if (key == 'menuOptions') {
                    this.options.menuOptions = $.extend({}, this._defaultMenuOptions, value);
                }
                else if (key == 'searchBoxAfter') {
                    this.options[key] = value;
                    this.options.menuOptions.showSearchBoxAfter = value;
                }
                else {
                    this.options[key] = value;
                    this._render();
                }

                return this;
            }
            else {
                return this.options[key];
            }
        },

        _setQueryObserver: function (remove) {
            var self = this;
            var query = this.getQuery();

            var queryObserver = function (event) {
                //if something has changed, and that is related to conditions
                if (!event.data)
                    return;

                var data = event.data;

                if (data.author !== self &&
                        event.data.changeType && event.data.changeType.indexOf("column") < 0) {
                    self.refresh();
                }

                if (self.options.autoEditNewCondition &&
                        (data.changeType == "condition.add" || 
                        data.changeType == "condition.change" &&
                            (data.what == "attribute" || data.what == "operator")))
                {
                    window.setTimeout(() => {
                        self.editConditionValue(data.condition);
                    }, 800); //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
                }
            };

            if (query) {
                if (remove && self._queryObserverId) {
                    query.removeChangedCallback(self._queryObserverId);
                }
                else {
                    self._queryObserverId = query.addChangedCallback(queryObserver);
                }
            }
        },


        _clear: function(isRefresh: boolean = false) {
            if (!isRefresh) {
                this.setActiveConditionWidget(null);
            }
            this.element.html('');
        },

        _refreshByQuery: function (rootBlock) {
            const rootCond = this.getQuery().getRootCondition();
            
            rootBlock.RootPredicate({ 
                queryPanel: this, 
                model: this.getModel() 
            });

            rootBlock.RootPredicate('init', rootCond, null, null);
            this._rootPredicateWidget = rootBlock.data('RootPredicate'); //jQuery before 1.9
            if (!this._rootPredicateWidget) {
                this._rootPredicateWidget = rootBlock.data('eqjs-RootPredicate'); //jQuery after 1.9
            }

            return rootBlock;
        },


        /// <method name="clearConditions">
        /// <summary>Clears the list of conditions in associated query and redraws a panel if needed</summary>
        /// <example>
        /// <code>
        ///     var QueryPanelDiv = $("#QueryPanel");
        ///     QueryPanelDiv.QueryPanel('clearConditions');
        /// </code>
        /// </example>
        /// </method>
        clearConditions: function (needRefresh) {
            var query = this.getQuery();

            query.clearConditions();

            if (needRefresh !== false) {
                this.refresh();
            }
        },

        /// <method name="clearQuery">
        /// <summary>Clears all parts (list of conditions, list of columns) in associated query and redraws a panel if needed</summary>
        /// <example>
        /// <code>
        ///     var QueryPanelDiv = $("#QueryPanel");
        ///     QueryPanelDiv.QueryPanel('clearQuery');
        /// </code>
        /// </example>
        /// </method>
        clearQuery: function (needRefresh) {
            var query = this.getQuery();

            query.clear();

            if (needRefresh !== false) {
                this.refresh();
            }
        },

        _fireQueryChange: function (changeType) {
            var self = this;

            var query = this.getQuery();
            query.fireChangedEvent({
                "source": self,
                "changeType": "query." + changeType
            }, true);
        },

        _fireEntitiesPopup: function (eventArgs) {
            var self = this;

            if (this.options.entitiesPopupHandler) {
                return this.options.entitiesPopupHandler({
                    "query": self.getQuery(),
                    "items": eventArgs.items
                });
            }
            else
                return false;
        },

        showEntitiesMenu: function(menuOptions) {
            var self = this;
            var items = self.options.entitiesMenu.PopupMenu("option", "items");
            var needRefresh = self._fireEntitiesPopup({
                "items" : items                
            });

            if (needRefresh) {
                self.options.entitiesMenu.PopupMenu("refreshItems", items);
            }

            self.options.entitiesMenu.PopupMenu("showMenu", menuOptions);
        },

        getEntitiesList: function (listOptions) {
            let model: DataModel = this.getModel();

            var listItems = model.getEntitiesTree(listOptions);
            if (this.options.entitiesListFilter) {
                this.options.entitiesListFilter(listItems, listOptions);
            }
            return listItems;
        },


        
        /// <method name="editConditionValue">
        /// <summary>
        /// Turns the row for condition passed in parameter into "edit" mode. 
        /// If no parameter is passed then it switch on edit mode for current active row.
        /// </summary>
        /// <example>
        /// <code>
        ///     var QueryPanelDiv = $("#QueryPanel");
        ///     QueryPanelDiv.QueryPanel('editConditionValue');
        /// </code>
        /// </example>
        /// </method>
        editConditionValue: function (condition) {
            //if conidition is not defined - then we take the first one in the query
            if (!condition && !this.isQueryNullOrEmpty()) {
                condition = this.getQuery().getRootCondition().conditions[0];
            }
            
            //if query is empty - go away
            if (!condition) return;

            //search for the row element which corresponds to the passed condition
            var condElement = this.element.find('[class*=eqjs-qp-row-condition]')
                .filter(function (this, index) {
                    return (this.condition == condition);
                });

            //take first value element is this row
            var valueElement = condElement.find('[class*=eqjs-qp-valueelement]').first();
            if (valueElement.length == 0) return;

            var data = $(valueElement).data();
            for (var prop in data) {
                if (prop.indexOf("ValueEditor_") >= 0) {
                    var valueEditor = data[prop];
                    valueEditor.showEditor();
                }
            }

            //$(firstValElement).ValueEditor("showEditor");
        },


        _createMenu: function (id, items, options) {
            if (this.isModelNullOrEmpty()) return null;

            var self = this;
            var menuDiv = $('<div></div>')
                .hide()
                .appendTo(self.element);

            var menuOptions = { items: items, id: id, domWriteItemsId: self.options.domWriteItemsId, isSubQuery: false, zIndex: 100000 };
            $.extend(menuOptions, self.options.menuOptions);
            $.extend(menuOptions, options);
            if (self.options.isSubQuery) {
                menuOptions.zIndex = self.options.dialogZIndex + 1000;
                menuOptions.isSubQuery = true;
            }

            menuDiv.PopupMenu(menuOptions);

            return menuDiv;
        },

        _createEntitiesMenu: function () {
            var menuId = this.element.attr('id') || "eq-querypanel";
            menuId += '-EntitiesMenu';

            return this._createMenu(menuId, this.options.entitiesList);
        },

        _createPredicateMenu: function (isRoot) {
            var menuId = this.element.attr('id') || "eq-querypanel";
            if (isRoot) {
                menuId += '-Root';
            };
            menuId += '-PredicateMenu';

            var items = [
                {
                    id: "addCondition",
                    text: eqi18n.getText('ButtonAddCondition')
                },
                {
                    id: "addPredicate",
                    text: eqi18n.getText('ButtonAddPredicate')
                }
            ];

            if (!isRoot) {
                items.push({
                    id: "enable",
                    text: eqi18n.getText('MenuEnable')
                });
                items.push({
                    id: "delete",
                    text: eqi18n.getText('ButtonDelete')
                });
            };

            return this._createMenu(menuId, items, { showSearchBoxAfter: 100});
        },

        _createConditionMenu: function () {
            var menuId = this.element.attr('id') || "eq-querypanel";
            menuId += '-ConditionMenu';

            var items = [
                {
                    id: "enable",
                    text: eqi18n.getText('MenuEnable')
                },
                {
                    id: "delete",
                    text: eqi18n.getText('ButtonDelete')
                }
            ];

            if (this.options.allowParameterization || this.options.allowInJoinConditions) {
                items.push({ id: "delimiter", text: "---" });
            };

            if (this.options.allowParameterization) {
                items.push({
                    id: "param",
                    text: eqi18n.getText('MenuParameterization')
                });
            };

            if (this.options.allowInJoinConditions) {
                items.push({
                    id: "inJoin",
                    text: eqi18n.getText('MenuJoinCond')
                });
            };

            return this._createMenu(menuId, items, { showSearchBoxAfter: 100 });
        },

        /// <method name="addNewCondition">
        /// <summary>
        /// Creates a new simple condition with attribute and operator based on their IDs passed in parameters 
        /// and then adds this new condition into the root predicate. 
        /// </summary>
        /// <param name="attrid" type="String">
        /// Attribute ID. By default attribute ID is equals to TableName.FieldName of corresponding column.
        /// </param>
        /// <param name="operid" type="String">
        /// Operator ID (e.g. 'Equals', 'StartsWith', etc).
        /// </param>
        /// <example>
        /// <code>
        ///     var QueryPanelDiv = $("#QueryPanel");
        ///     QueryPanelDiv.QueryPanel('addNewCondition', 'Orders.Paid', 'IsTrue');
        /// </code>
        /// </example>
        /// </method>
        addNewCondition: function (attrid, operid) {
            var self = this;

            if (self._rootPredicateWidget) {
                return self._rootPredicateWidget.addNewCondition(attrid, operid);
            }
            return null;
        },

        addNewConditionIntoActivePredicate: function (attrid, operid) {
            var self = this;

            if (this._activeConditionWidget) {
                var activePredicateWidget;
                if (this._activeConditionWidget.isPredicate()) {
                    activePredicateWidget = this._activeConditionWidget;
                }
                else {
                    activePredicateWidget = this._activeConditionWidget._parentPredicateWidget;
                }

                return activePredicateWidget.addNewCondition(attrid, operid);
            }
            else {
                return this.addNewCondition(attrid, operid);
            }

        },

        refresh: function () {
            let activeCondition = this.options.activeCondition;
            this._render(true);
            this._updPwby();

            let query = this.getQuery();
            if (!activeCondition || query.isEmptyConditions()) {
                this._checkActivateRootPredicate();
            }
        },

        resize: function () {
            this.refresh();
        },

        /// <method name="setActiveConditionWidget">
        /// <summary>Activates the particular condition in the panel</summary>
        /// <param name="conditionWidget" type="Object">
        /// <summary>The ConditionRow_SMPL or ConditionRow_PDCT object to activate.</summary>
        /// </param>
        /// </method>
        setActiveConditionWidget: function (conditionWidget) {
            this.deactivateConditionWidget();

            this._activeConditionWidget = conditionWidget;
            if (this._activeConditionWidget) {
                this._activeConditionWidget.internalActivate();
                this.options.activeCondition = this._activeConditionWidget.getCondition();
            }
        },

        deactivateConditionWidget: function () {
            if (this._activeConditionWidget) {
                this._activeConditionWidget.internalDeactivate();
                this.options.activeCondition = null;
            }
        },

        predicateContainsCondition: function (predicate, condition) {
            var self = this;
            if (!predicate || !condition) { return false; }

            if (predicate.conditions) {
                var condLength = predicate.conditions.length;
                for (var i = 0; i < condLength; i++) {
                    if (predicate.conditions[i] == condition) { return true; }

                    if (self.predicateContainsCondition(predicate.conditions[i], condition)) { return true; }
                }
            }

            return false;
        },

        getNewPredId: function () {
            if (this.element.attr('id')) {
                return this.element.attr('id') + '-pred-' + ++this._globalPredCounter;
            }
        },

        getNewCondId: function () {
            if (this.element.attr('id')) {
                return this.element.attr('id') + '-cond-' + ++this._globalCondCounter;
            }
        }
    });
}
