(function($) {
    $.widget('ui.combobox', {
        options: {
            imagesUrl: '../themes/default/images/astrolabe/',
            defaultbehaviour: true,
            noneSelectedLabel: '(none)',
            addItemPlaceholder: 'Add tree',
            itemExistsError: 'Item already exists in list',
            maxLength: 256,
            baseUrl:''
        },

        _create: function() {
            var $self = this;

            var $dl = $('<dl>');
            $dl.addClass('combobox');

            $self._dt = $('<div class="btn-group"><button class="btn label-placeholder"></div></div>');

            $self._selectedId = null;
            $self._selectedItem = null;

            $self._selectedLabel = $('<span></span>');
            $self._selectedLabel.addClass('selectedLabel');
            $self._selectedLabel.html($self.options.noneSelectedLabel);
            $self._dt.find('.label-placeholder').append($self._selectedLabel);


            $self._dt.append('<button class="btn dropdown-toggle"> <span class="bi bi-chevron-down"></span> </button>');

            $self._dt.find('.dropdown-toggle').click(function(event) {
                $self._onClickHeader($self, event);
                event.stopPropagation();
            });

            $self._dt.find('.label-placeholder').click(function(event) {
                $self._onClickHeader($self, event);
                event.stopPropagation();
            });


            $dl.append($self._dt);

            $self._dd = $('<dd class="open">');

            $self._ul = $('<ul class="dropdown-menu">');

            var $noneItem = $('<li>');
            $noneItem.click(function(event) {
                $self._setSelectedItem($self, null);
                event.stopPropagation();
            });
            var $noneItemLabeldiv = $('<div>');
            $noneItemLabeldiv.addClass('itemLabel');
            $noneItemLabelspan = $('<span></span>');
            $noneItemLabelspan.text($self.options.noneSelectedLabel);
            $noneItemLabeldiv.append($noneItemLabelspan);
            $noneItem.append($noneItemLabeldiv);
            $self._ul.prepend($noneItem);



            $self._ul.append('<li class="divider"></li>');

            $self._addNewTreeItemButton();
            $self._addTreeSuscribeButton();


            $self._dd.append($self._ul);
            $dl.append($self._dd);
            $self._setExpanded(false);

            $self.element.append($dl);
        },

        refresh: function() {
                var id = this._dt.find('.label-placeholder').find('.selectedLabel').attr('itemid');
                this._setSelectedItem(this, id);
        },

        _addNewTreeItemButton: function() {

            var $self = this;
            var $addItem = $('<li>');
            $addItem.addClass('addItem ');

            var $addButton = $('<span>Add new categorization</span>');
            $addButton.addClass('addButton itemLabel');
            $addButton.click(function(event) {
                $self.initializeAddNewTreeDialog();
            });
            $addItem.append($addButton);
            $self._ul.append($addItem);
        },

        _addTreeSuscribeButton: function() {

            var $self = this;
            var $addItem = $('<li>');
            $addItem.addClass('addItem ');

            var $addButton = $('<span>Edit subscriptions</span>');
            $addButton.addClass('subscribeButton itemLabel');
            $addButton.click(function(event) {
                $self.initializeTreeSubscribeDialog();
            });
            $addItem.append($addButton);
            $self._ul.append($addItem);

        },

        _init: function() {
            var $self = this;
            $self._id = common.randomUUID();
            $self._selectedId = null;
        },

        initializeTreeSubscribeDialog: function() {
            var $self = this;

            var subscribeDialogBody = {
                'header':"<h1>Subscription list</h1>",
                'body_url':$self._requestUrls.subscribeTreeDialog($self),
                'keyboard': true,
                'backdrop':true,
                'onEscape': function() {
                // do close functions such as refreshing tree.


                },
                'load_callback': function() {

                    //bind subscribe and unsubscribe key

                    $(document).off('click','button.nav-tree-subscribe');
                    $(document).off('click','button.nav-tree-unsubscribe');
                    $(document).off('click','button.nav-tree-copylocal');


                    $(document).on('click','button.nav-tree-subscribe',function(){
                        var $parentLi = $(this).closest('li');
                        var id = $parentLi.attr('id');
                        var name = $parentLi.attr('data-name');
                        var sharedFrom = $parentLi.attr('data-sharedFrom');
                        $self.subscribeTree(id,name,sharedFrom);
                        $parentLi.find('.subscribe-panel').hide();
                        $parentLi.find('.unsubscribe-panel').show();

                    });

                    // bind for copy as local
                    $(document).on('click','button.nav-tree-copylocal',function(){
                        var $parentLi = $(this).closest('li');
                        var id = $parentLi.attr('id');
                        var sharedFrom = $parentLi.attr('data-sharedFrom');
                        $self.copyTree(id,sharedFrom);
                        $parentLi.find('.subscribe-panel').hide();
                        $parentLi.find('.unsubscribe-panel').hide();

                    });

                    //bind subscribe and unsubscribe key
                    $(document).on('click','button.nav-tree-unsubscribe',function(){
                        var $parentLi = $(this).closest('li');
                        var id = $parentLi.attr('id');
                        $self.unsubscribeTree(id);
                        $parentLi.find('.unsubscribe-panel').hide();
                        $parentLi.find('.subscribe-panel').show();
                    });
                }
            };
            $("<div></div>")
                .dialog_modal({
                    passedArgs: ['',
                        [{
                            "label" : "Close",
                            "class" : "btn btn-large",
                            "callback": function() {}
                        }
                        ],subscribeDialogBody],
                })

            $(document).off('focusin.modal');
        },

        copyTree: function(id,sharedFrom) {
            var $self = this;
            var url = $self._requestUrls.copyTree($self,id,sharedFrom);
            $.ajax({
                type: 'PUT',
                url: url,
                dataType:'JSON',
                success:function(data) {

                    var $profile = {
                        'id':data.id,
                        'defaultTree':false,
                        'name':data.name,
                        'shared':false,
                        'sharedFrom':[],
                        'sharedPermission':[],
                        'global':false
                    };
                    $self.addItem($profile);

                },
                error: function() {
                }
            });
        },

        subscribeTree: function(id,name,sharedFrom) {
            var $self = this;
            var url = $self._requestUrls.subscribeTree($self,id);
            $.ajax({
                type: 'PUT',
                url: url,
                success:function() {

                    var $profile = {
                        'id':id,
                        'defaultTree':true,
                        'name':name,
                        'shared':true,
                        'sharedFrom':sharedFrom,
                        'sharedPermission':[],
                        'global':false
                    };

                    $self.addItem($profile);

                },
                error: function() {
                }
            });
        },

        unsubscribeTree: function(id) {
            var $self = this;
            var url = $self._requestUrls.subscribeTree($self,id);
            $.ajax({
                type: 'DELETE',
                url: url,
                success:function() {
                    var $profile = {
                        id:id
                    };
                    $self.removeItem($profile);
                },
                error: function() {
                }
            });



        },


        initializeAddNewTreeDialog: function() {
            var $self = this;

            function showNodeAdditionValidationError(validation) {
                var $errorKey = validation.key;
                $('#astrolabe-add-node-label-error').html('');
                $('#astrolabe-add-node-class-error').html('');
                if ($errorKey == 'label') {
                    $('#astrolabe-add-node-label-error').html(validation.text);
                    $('#astrolabe-add-node-label').focus();
                } else if ($errorKey== 'classRegex') {
                    $('#astrolabe-add-node-class-error').html(validation.text);
                    $('#astrolabe-add-node-class').focus();
                }
            }

            var okButtonInTreeDialog = {
                "label" : "Ok",
                "class" : "btn-primary btn-large",
                "callback": function() {
                    var treeName = $('input#astrolabe-add-tree-label').val();
                    var treeValidationResult = $self.treeTitleValidation(treeName);
                    if (treeValidationResult !== true) {
                        var $error = treeValidationResult['error'];
                        $('#astrolabe-add-tree-label-error').html($error);
                        $('input#astrolabe-add-tree-label').focus();
                        return false;
                    }

                    var treenodes = [];
                    $('span.treeNodes').each(function(index) {
                        var $nodeLabel = $(this).text();
                        var $nodeClassExpression = $(this).attr('data-classRegex');
                        treenodes.push({
                            label:$nodeLabel,
                            classRegex:$nodeClassExpression
                        }
                        );
                    });

                    // check for the input fields as well
                    var inputLabel = $('#astrolabe-add-node-label').val();
                    var inputClassRegex =$('#astrolabe-add-node-class').val();
                    // we have some input
                    if (inputLabel || inputClassRegex) {
                        var validation = $self.nodeAddValidation(inputLabel,inputClassRegex);
                        if (validation === true) {
                            treenodes.push({
                                label:inputLabel,
                                classRegex:inputClassRegex
                            });
                        } else {
                            showNodeAdditionValidationError(validation);
                            return false;
                        }
                    }

                    var sharedPermission = $('select#astrolabe-add-tree-roles-multiselect').val()
                    var global = $('input#astrolabe-add-tree-make-global').is(':checked') ? true : false;
                    var $result = $self.addTree(treeName,treenodes,sharedPermission,global);

                    return $result;

                }

            };

            var cancelButtonInTreeDialog =  {
                "label" : "Cancel",
                "class" : "btn btn-large"
            };

            var addTreeDialogBody = {
                'header':"<h1>Categorize your host</h1>",
                'body_url':$self._requestUrls.addTreeDialog($self),
                'load_callback': function() {
                    processPageBeforeLeave();
                    $('.addNodeForTree').click(function() {

                        var label = $('#astrolabe-add-node-label').val();
                        var classRegex =$('#astrolabe-add-node-class').val();
                        var validation = $self.nodeAddValidation(label,classRegex);
                        if (validation === true) {
                            var $labelWrapper = $('<span class="treeNodes label" style="margin-right:10px;display:inline-block;">'+label+'</span>');
                            $labelWrapper.attr('data-classRegex',classRegex);

                            $('.addedNodesLabel').show();
                            $('div.addedTreeNodes').append($labelWrapper);
                            $('#astrolabe-add-node-label').val('');
                            $('#astrolabe-add-node-class').val('');
                            $('#astrolabe-add-node-label').val('');
                            $('#astrolabe-add-node-class-error').html('');
                            $('#astrolabe-add-node-label-error').html('');
                        } else {
                            showNodeAdditionValidationError(validation);
                        }
                    });
                },
                'onEscape': function(){}
            };

            $(document).on("hidden.bs.modal", function (e) {
                unbindBeforeUnload();
            });

            $("<div></div>")
                .dialog_modal({
                    passedArgs: ['', [cancelButtonInTreeDialog, okButtonInTreeDialog],addTreeDialogBody],
                })

            $(document).off('focusin.modal');

            return;

        },


        nodeAddValidation: function (label,classRegex) {
            var errorObj=[];
            if (label == '') {
                errorObj = {
                    key:'label',
                    text:'Label cannot be empty.'
                };
                return errorObj;
            }
            else if (!/^[a-zA-Z0-9 _-]{1,100}$/.test(label)) {
                errorObj = {
                    key:'label',
                    text:'Label can only contain alphanumeric characters, spaces, "_" or "-" (max 100 characters).'
                };
                return errorObj;
            }

            if (classRegex == '') {
                errorObj = {
                    key:'classRegex',
                    text:'Class regex cannot be empty.'
                };
                return errorObj;
            }
            else if (!common.isValidClassExpression(classRegex)) {
                errorObj = {
                    key:'classRegex',
                    text:'Invalid class regex.'
                };
                return errorObj;
            }
            return true;

        },

        treeTitleValidation:function(treeTitle,oldTitle) {
            var $self = this;
            var errorObj=[];
            var checkDuplicateName = oldTitle || true;

            if (oldTitle && oldTitle==treeTitle) {
                checkDuplicateName = false;
            }

            if(treeTitle.length <=0) {
                errorObj['error'] = 'The tree title cannot be empty.';
                return errorObj;
            } else if (!/^[a-zA-Z0-9-_ ]+$/.test(treeTitle)) {
                errorObj['error'] = 'The tree title can only contain alpha numeric characters with "_" or "-".';
                return errorObj;
            } else if (checkDuplicateName && $self._itemExists(treeTitle)) {
                errorObj['error'] = 'A tree with this name already exist';
                return errorObj;
            }
            return true;
        },


        addTree: function(treeName,treenodes,sharedPermission,global) {
            var $self = this;
            var $result = $self.onAddItem(treeName,treenodes,sharedPermission,global);

            if ($result) {
                $("#addNewTreeDialog").modal('hide');
                $("#addNewTreeDialog").remove();
                return true;
            }

            return false;
        },

        onAddItem: function(id,treeNodes,sharedPermission,global) {
            var $self = this;
            if (id !== undefined &&
                id !== null &&
                id.length > 0) {
                var $profile = {
                    'id':id,
                    'defaultTree':false,
                    'name':id,
                    'shared':false, // its a private tree not shared one
                    'sharedFrom':null,
                    'sharedPermission':sharedPermission,
                    'global':global
                };
                var $item = $self.addItem($profile);
                if ($item) {
                    $self._trigger('itemAdded', null, {
                        'name': id,
                        'id':id,
                        'nodes':treeNodes || [],
                        'targetItem' : $item,
                        'sharedPermission':sharedPermission,
                        'global':global
                    });
                    $self._setSelectedItem($self, id, false);
                    $self._setExpanded(false);
                    return true;
                }
            }

            return false;
        },

        clear: function() {
            var $self = this;
            $self._ul.remove('li');
        },

        _setSelectedItem: function($self, id, trigger) {
            $self._selectedId = id || null;
            var $item =  $('li[itemid="'+id+'"]');
            $self._selectedItem = $item;
            var $name = $item.find('.itemLabel span').text();
            if ($self._selectedId === null) {
                $self._selectedLabel.html($self.options.noneSelectedLabel);
                $self._selectedLabel.attr('itemid', '');
            } else {

                // check for invalid id here
                if (!$item.length) {
                    // we have invalid id here
                    var $osItem = $self._ul.find('.itemLabel span').filter(':contains("OS")');
                    if ($osItem.length) {
                        $name = 'OS';
                        $self._selectedId = $osItem.closest('li').attr('itemid');
                    } else {
                        $name = null;
                        $self._selectedId = null;
                    }
                }

                $self._selectedLabel.text(decodeURIComponent($name));
                $self._selectedLabel.attr('itemid', $self._selectedId);
            }

            $self._setExpanded(false);
            if(trigger===undefined){
                var defaultValue = $item.attr('default') == "true" ? true : false;
                var sharedTree =  $item.attr('data-sharedtree') == "true" ? true : false;
                var sharedFrom =  $item.attr('data-sharedfrom');

                $self._trigger('itemSelected', null, {
                    id: $self._selectedId,
                    defaultProfile: defaultValue,
                    sharedTree: sharedTree,
                    sharedFrom:sharedFrom
                });
            }

        },

        _itemExists: function(name) {
            var $self = this;

            var found = false;
            $self._ul.find('li').each(function(index, item) {
                if ($(item).find('.itemLabel span').text() == name && $(item).attr('data-sharedtree') == "false") {
                    found = true;
                }
            });
            return found;
        },


        addItemEditControl: function($item) {
            var $self = this;
            var $editIcon = $('<i class="icon-pencil icon-white editIcon pull-right"></i>');
            $editIcon.click(function(event) {
                event.stopPropagation();
                var $li  = $(this).closest('li');
                var id  = $li.attr('itemId');
                var oldTitle =$li.find('.itemLabel span').text();
                var okButtonInEditTreeDialog = {
                    "label" : "Ok",
                    "class" : "btn-primary btn-large",
                    "callback": function() {
                        var $newName = $('input#astrolabe-add-tree-label').val();
                        var sharedPermission = $('select#astrolabe-add-tree-roles-multiselect').val()
                        var global = $('input#astrolabe-add-tree-make-global').is(':checked') ? 1 : 0;
                        var treeValidationResult = $self.treeTitleValidation($newName,oldTitle);
                        if (treeValidationResult !== true) {
                            var $error = treeValidationResult['error'];
                            $('#astrolabe-add-tree-label-error').html($error);
                            $('input#astrolabe-add-tree-label').focus();
                            return false;
                        } else {
                            $.ajax({
                                type: 'POST',
                                url: $self._requestUrls.renameTreeDialog($self,id),
                                data: {
                                    id:id,
                                    'newname':$newName,
                                    'globalTree':global,
                                    'sharedPermission':sharedPermission
                                },
                                success:function() {
                                    $li.find('.itemLabel span').text($newName);
                                    $self._setSelectedItem($self,id);
                                },
                                error: function() {
                                    $('#astrolabe-add-tree-label-error').html('Something went wrong while updating. Please try again.');
                                }
                            });
                        }
                    }

                };

                var cancelButtonInTreeDialog =  {
                    "label" : "Cancel",
                    "class" : "btn btn-large"
                };


                var editTreeDialogBody = {
                    'header':"<h1>Edit tree</h1>",
                    'body_url':$self._requestUrls.editTreeDialog($self,id),
                    'load_callback': function() {
                    },
                    'onEscape': function(){}
                };
                $("<div></div>")
                    .dialog_modal({
                        passedArgs: ['',
                            [cancelButtonInTreeDialog, okButtonInEditTreeDialog],
                            editTreeDialogBody],
                    })

                $(document).off('focusin.modal');
                return;
            });
            var $labelElement = $item.find('.itemLabel:first-child');
            $labelElement.append($editIcon);
        },

        addItemDeleteControl: function($item) {
            var $self = this;
            var $deleteIcon = $('<i>');
            $deleteIcon.addClass('icon-remove icon-white deleteIcon pull-right');
            $deleteIcon.click(function(event) {
                var $dialog=$self._confirmationDialog($item,$(this).closest('li').attr('itemId'));
                $dialog.dialog('open');
                event.stopPropagation();
            });
            var $labelElement = $item.find('.itemLabel:first-child');
            $labelElement.append($deleteIcon);
        },

        addItemSharedControl:function($item) {
            var $self = this;
            var sharedTree = $item.attr('data-sharedtree');
            var $labelElement = $item.find('.itemLabel:first-child');
            if (typeof sharedTree !== 'undefined' && sharedTree !== false && sharedTree != "false" ) {
                // check if its global tree
                var globalTree = $item.attr('data-global');
                var iconClass = globalTree == "true" ?  "icon-globe" : "icon-share";
                var $iconElement = $('<i class="icon"></i>').addClass(iconClass);
                $labelElement.prepend($iconElement)
            } else {
                $labelElement.prepend('<i class="icon icon-user"></i>');
            }
        },



        addItemControls: function ($item) {
            var $self = this;
            var defaultTree = $item.attr('default');

            if (defaultTree == 'false') {
                $self.addItemDeleteControl($item);
                $self.addItemEditControl($item);
            }
            $self.addItemSharedControl($item);
        },


        addItem: function(profile) {

            var $self = this;
            var id = profile.id;
            var defaultTree = profile.defaultTree;
            var name = profile.name;


            if ($self._itemExists(name)) {
                bootbox.alert($self.options.itemExistsError);
                $(document).off('focusin.modal');
                return false;
            }
            var $li = $('<li>');
            $li.attr('itemId', id);
            $li.attr('default', defaultTree);
            $li.attr('data-sharedTree', profile.shared);
            $li.attr('data-sharedFrom', profile.sharedFrom);
            $li.attr('data-sharedPermission', profile.sharedPermission);
            $li.attr('data-global', profile.global);
            $li.click(function(event) {
                $self._setSelectedItem($self, $(this).attr('itemId'));
                event.stopPropagation();
            });

            var $labelDiv = $('<div>');
            $labelDiv.addClass('itemLabel');

            var $labelSpan = $('<span>');

            var truncateName = name;
            if (name.length > 30) {
                truncateName = truncateName.substr(0,25) + '...';
            }

            $labelSpan.text(decodeURIComponent(truncateName));
            $labelDiv.append($labelSpan);
            $li.append($labelDiv);
            $self.addItemControls($li);
            $self._ul.prepend($li);
            return $li;
        },

        removeItem:function(profile) {
            var $self = this;
            var id = profile.id;
            $self._ul.find('li[itemid='+id+']').remove();
        },

        selectItem:function(id){
            var $self=this;
            $self._setSelectedItem($self,id);
            $self._setExpanded(false);
        },
        getItemId: function(name) {
            var returnVal = null;
            var $self = this;
            $self._ul.find('li').each(function(index, item) {
                if ($(item).find('.itemLabel span').text() == name) {
                    returnVal =  $(item).attr('itemid');
                    return false; // break each loop
                }
            });
            return returnVal;
        },
        _onClickHeader: function($self, event) {
            var isExpanded=$self._dd.hasClass('open');
            $self._setExpanded(!isExpanded);
        },

        _setExpanded: function(expanded) {
            var $self = this;

            if (expanded === true) {
                $('html').on('click.' + $self._id, function(event) {
                    if ($(event.target).parents().is($self.element) === false) {
                        $self._setExpanded(false);
                    }
                });
                $self._dd.addClass('open');
            }
            else {
                $('html').unbind('click.' + $self._id);
                $self._dd.removeClass('open');
            }


        },

        updateSelectedId: function($id) {
            var $self = this;
            $self._selectedLabel.attr('itemid',$id);
            $self._selectedItem.attr('itemId',$id);
        },

        _confirmationDialog:function(element,id){
            var $self=this;
            var $confirmation=$( "<div>" ).html('Are you sure you want to permanently remove this tree?').dialog({
                title: "Delete this view?",
                resizable: false,
                modal: true,
                buttons: {
                    Cancel: function() {
                        $(this).dialog('destroy');
                        $(this).dialog('close');
                        $(this).remove();
                    },
                    "Delete": function() {
                        element.remove();
                        $self._setSelectedItem($self, null);
                        $self._trigger('itemDeleted', null, {
                            id: id
                        });
                        $(this).dialog('destroy');
                        $(this).dialog('close');
                        $(this).remove();
                    }
                },
                open: function(event, ui) {
                    $(this).parent().find(":button:contains('Delete')").addClass('btn btn-danger btn-large').focus();
                    $(this).parent().find(":button:contains('Cancel')").addClass('btn btn-large');
                },
                close:function(event,ui){  //strongly need to clear out the cache.
                    $(this).dialog('destroy');
                    $(this).dialog('close');
                    $(this).remove();
                }
            });
            $('.ui-icon-closethick').html('×');
            return $confirmation;
        },



        _requestUrls: {

            addTreeDialog: function(self) {
                var url = self.options.baseUrl + '/widget/astrolabeAddTreeDialog';
                return url;
            },
            editTreeDialog:function (self,id) {
                var url = self.options.baseUrl + '/widget/astrolabeEditTreeDialog/'+id;
                return url;
            },
            subscribeTreeDialog: function(self) {
                var url = self.options.baseUrl + '/widget/astrolabeSubscribeTreeDialog';
                return url;
            },
            renameTreeDialog: function(self,id) {
                var url = self.options.baseUrl + '/astrolabe/profile/'+id;
                return url;
            },
            subscribeTree:function(self,id) {
                var url = self.options.baseUrl + '/astrolabe/subscribe/'+id;
                return url;
            },
            copyTree:function(self,id,sharedFrom) {
                var url = self.options.baseUrl + '/astrolabe/copy/'+id+'/'+sharedFrom;
                return url;
            }
        },


        destroy: function() {
            $.Widget.prototype.destroy.call(this);
        }

    });

    $.extend($.ui.combobox, {
        instances: []
    });
})(jQuery);
