// Tests only the behaviours specific to our default implementation of the list item
describe("Ext.list.TreeItem", function() {

    var root, list, store, sampleData;

    var Model = Ext.define(null, {
        extend: 'Ext.data.TreeModel',
        fields: ['customField']
    });

    function makeList(cfg, noStore) {
        if (!store && !noStore) {
            store = new Ext.data.TreeStore({
                model: Model,
                root: {
                    expanded: true,
                    children: sampleData
                }
            });
        }

        list = new Ext.list.Tree(Ext.apply({
            store: store,
            animation: false
        }, cfg));
        list.render(Ext.getBody());

        if (list.getStore()) {
            root = list.getStore().getRoot();
        }
    }

    beforeEach(function() {
        sampleData = [{
            id: 'i1',
            text: 'Item 1',
            iconCls: 'iconA',
            children: [{
                id: 'i11',
                text: 'Item 1.1',
                leaf: true
            }, {
                id: 'i12',
                text: 'Item 1.2',
                leaf: true
            }]
        }, {
            id: 'i2',
            text: 'Item 2',
            expandable: false
        }, {
            id: 'i3',
            iconCls: 'iconB',
            text: 'Item 3',
            children: []
        }, {
            id: 'i4',
            text: 'Item 4',
            expanded: true,
            children: [{
                id: 'i41',
                iconCls: 'iconC',
                text: 'Item 4.1'
            }, {
                id: 'i42',
                text: 'Item 4.2',
                iconCls: null
            }, {
                id: 'i43',
                text: 'Item 4.3'
            }]
        }];
    });

    afterEach(function() {
        root = sampleData = store = list = Ext.destroy(list, store);
    });

    function byId(id) {
        return store.getNodeById(id);
    }

    function getItem(id) {
        return list.getItem(byId(id));
    }

    describe("items", function() {
        beforeEach(function() {
            makeList();
        });

        describe("at creation", function() {
            it("should render child items in order", function() {
                var item = getItem('i1'),
                    itemContainer = item.itemContainer;

                expect(itemContainer.dom.childNodes[0]).toBe(getItem('i11').el.dom);
                expect(itemContainer.dom.childNodes[1]).toBe(getItem('i12').el.dom);

                item = getItem('i4');
                itemContainer = item.itemContainer;

                expect(itemContainer.dom.childNodes[0]).toBe(getItem('i41').el.dom);
                expect(itemContainer.dom.childNodes[1]).toBe(getItem('i42').el.dom);
                expect(itemContainer.dom.childNodes[2]).toBe(getItem('i43').el.dom);
            });

            it("should set the text on the textElement", function() {
                expect(getItem('i1').textElement.dom).hasHTML('Item 1');
                expect(getItem('i11').textElement.dom).hasHTML('Item 1.1');
                expect(getItem('i12').textElement.dom).hasHTML('Item 1.2');

                expect(getItem('i2').textElement.dom).hasHTML('Item 2');

                expect(getItem('i3').textElement.dom).hasHTML('Item 3');

                expect(getItem('i4').textElement.dom).hasHTML('Item 4');
                expect(getItem('i41').textElement.dom).hasHTML('Item 4.1');
                expect(getItem('i42').textElement.dom).hasHTML('Item 4.2');
                expect(getItem('i43').textElement.dom).hasHTML('Item 4.3');
            });

            describe("leafCls", function() {
                it("should have the leafCls if an item is a leaf", function() {
                    Ext.Array.forEach(['i11', 'i12'], function(id) {
                        var item = getItem(id);
                        expect(item.element).toHaveCls(item.leafCls);
                    });

                    Ext.Array.forEach(['i1', 'i2', 'i3', 'i4', 'i41', 'i42', 'i43'], function(id) {
                        var item = getItem(id);
                        expect(item.element).not.toHaveCls(item.leafCls);
                    });
                });
            });

            describe("iconCls", function() {
                it("should add the withIconCls and set the iconCls if there is an iconCls", function() {
                    var i1 = getItem('i1'),
                        i3 = getItem('i3'),
                        i41 = getItem('i41');

                    expect(i1.iconElement).toHaveCls('iconA');
                    expect(i3.iconElement).toHaveCls('iconB');
                    expect(i41.iconElement).toHaveCls('iconC');

                    expect(i1.element).toHaveCls(i1.withIconCls);
                    expect(i3.element).toHaveCls(i3.withIconCls);
                    expect(i41.element).toHaveCls(i41.withIconCls);
                });

                it("should not have the withIconCls if there is no iconCls", function() {
                    Ext.Array.forEach(['i11', 'i12', 'i2', 'i4', 'i42', 'i43'], function(id) {
                        var item = getItem(id);
                        expect(item.element).not.toHaveCls(item.withIconCls);
                    });
                });

                it("should have the hideIconCls if the iconCls is null", function() {
                    var item = getItem('i42');
                    expect(item.element).toHaveCls(item.hideIconCls);
                });

                it("should not have the hideIconCls if the iconCls is not null", function() {
                    Ext.Array.forEach(['i1', 'i11', 'i12', 'i2', 'i3', 'i4', 'i41', 'i43'], function(id) {
                        var item = getItem(id);
                        expect(item.element).not.toHaveCls(item.hideIconCls);
                    });
                });
            });

            describe("expanded/collapsed", function() {
                it("should add the collapsedCls if the item is collapsed and expandable", function() {
                    Ext.Array.forEach(['i1', 'i41', 'i42', 'i43'], function(id) {
                        var item = getItem(id);
                        expect(item.element).toHaveCls(item.collapsedCls);
                    });

                    Ext.Array.forEach(['i11', 'i12', 'i2', 'i3', 'i4'], function(id) {
                        var item = getItem(id);
                        expect(item.element).not.toHaveCls(item.collapsedCls);
                    });
                });

                it("should add the expandedCls if the item is expanded and expandable", function() {
                    Ext.Array.forEach(['i4'], function(id) {
                        var item = getItem(id);
                        expect(item.element).toHaveCls(item.expandedCls);
                    });

                    Ext.Array.forEach(['i1', 'i11', 'i12', 'i2', 'i3', 'i41', 'i42', 'i43'], function(id) {
                        var item = getItem(id);
                        expect(item.element).not.toHaveCls(item.expandedCls);
                    });
                });
            });

            describe("expandable", function() {
                it("should add the expandableCls if the item is expandable", function() {
                    Ext.Array.forEach(['i1', 'i4', 'i41', 'i42', 'i43'], function(id) {
                        var item = getItem(id);
                        expect(item.element).toHaveCls(item.expandableCls);
                    });

                    Ext.Array.forEach(['i11', 'i12', 'i2', 'i3'], function(id) {
                        var item = getItem(id);
                        expect(item.element).not.toHaveCls(item.expandableCls);
                    });
                });
            });
        });

        describe("dynamic store modifications", function() {
            describe("adding nodes", function() {
                it("should insert nodes in the right position", function() {
                    byId('i1').insertBefore({
                        id: 'i9'
                    }, byId('i12'));

                    var childNodes = getItem('i1').itemContainer.dom.childNodes;
                    expect(childNodes[0]).toBe(getItem('i11').el.dom);
                    expect(childNodes[1]).toBe(getItem('i9').el.dom);
                    expect(childNodes[2]).toBe(getItem('i12').el.dom);
                });

                it("should append nodes to the right position", function() {
                    byId('i1').appendChild({
                        id: 'i9'
                    });

                    var childNodes = getItem('i1').itemContainer.dom.childNodes;
                    expect(childNodes[0]).toBe(getItem('i11').el.dom);
                    expect(childNodes[1]).toBe(getItem('i12').el.dom);
                    expect(childNodes[2]).toBe(getItem('i9').el.dom);
                });

                it("should add the expandableCls when adding the first item", function() {
                    var item = getItem('i3'),
                        el = item.element;

                    expect(el).not.toHaveCls(item.expandableCls);
                    byId('i3').appendChild({
                        id: 'i9'
                    });
                    expect(el).toHaveCls(item.expandableCls);
                });
            });

            describe("removing nodes", function() {
                it("should remove the element from the DOM", function() {
                    var item = getItem('i42'),
                        itemContainer = getItem('i4').itemContainer;

                    expect(itemContainer.contains(item.el)).toBe(true);
                    expect(itemContainer.child('#' + item.id)).toBe(item.el);
                    byId('i4').removeChild(byId('i42'));
                    expect(item.destroyed).toBe(true);
                    expect(itemContainer.child('#' + item.id)).toBeNull();
                });

                it("should remove the expandableCls when removing the last item", function() {
                    var item = getItem('i1'),
                        el = item.element;

                    byId('i1').removeChild(byId('i12'));
                    expect(el).toHaveCls(item.expandableCls);
                    byId('i1').removeChild(byId('i11'));
                    expect(el).not.toHaveCls(item.expandableCls);
                });
            });

            describe("collapse", function() {
                describe("when expanded", function() {
                    it("should have the collapsedCls", function() {
                        var item = getItem('i4');
                        byId('i4').collapse();
                        expect(item.element).toHaveCls(item.collapsedCls);
                    });

                    it("should not have the expandedCls", function() {
                        var item = getItem('i4');
                        byId('i4').collapse();
                        expect(item.element).not.toHaveCls(item.expandedCls);
                    });

                    it("should hide the itemContainer", function() {
                        var item = getItem('i4');
                        byId('i4').collapse();
                        expect(item.itemContainer.isVisible()).toBe(false);
                    });
                });

                describe("when collapsed", function() {
                    it("should have the collapsedCls", function() {
                        var item = getItem('i1');
                        byId('i1').collapse();
                        expect(item.element).toHaveCls(item.collapsedCls);
                    });

                    it("should not have the expandedCls", function() {
                        var item = getItem('i1');
                        byId('i1').collapse();
                        expect(item.element).not.toHaveCls(item.expandedCls);
                    });

                    it("should hide the itemContainer", function() {
                        var item = getItem('i1');
                        byId('i1').collapse();
                        expect(item.itemContainer.isVisible()).toBe(false);
                    });
                });
            });

            describe("expand", function() {
                describe("when collapsed", function() {
                    it("should have the expandedCls", function() {
                        var item = getItem('i1');
                        byId('i1').expand();
                        expect(item.element).toHaveCls(item.expandedCls);
                    });

                    it("should not have the collapsedCls", function() {
                        var item = getItem('i1');
                        byId('i1').expand();
                        expect(item.element).not.toHaveCls(item.collapsedCls);
                    });

                    it("should show the itemContainer", function() {
                        var item = getItem('i1');
                        byId('i1').expand();
                        expect(item.itemContainer.isVisible()).toBe(true);
                    });

                    describe("loading", function() {
                        it("should have the loadingCls while loading", function() {
                            MockAjaxManager.addMethods();
                            var item = getItem('i41');
                            expect(item.element).not.toHaveCls(item.loadingCls);
                            item.expand();
                            expect(item.element).toHaveCls(item.loadingCls);
                            Ext.Ajax.mockComplete({
                                status: 200,
                                responseText: '[]'
                            });
                            expect(item.element).not.toHaveCls(item.loadingCls);
                            MockAjaxManager.removeMethods();
                        });
                    });
                });

                describe("when expanded", function() {
                    it("should have the expandedCls", function() {
                        var item = getItem('i4');
                        byId('i4').expand();
                        expect(item.element).toHaveCls(item.expandedCls);
                    });

                    it("should not have the collapsedCls", function() {
                        var item = getItem('i4');
                        byId('i4').expand();
                        expect(item.element).not.toHaveCls(item.collapsedCls);
                    });

                    it("should hide the itemContainer", function() {
                        var item = getItem('i4');
                        byId('i4').expand();
                        expect(item.itemContainer.isVisible()).toBe(true);
                    });
                });
            });

            describe("updating node fields", function() {
                it("should update the text when the text is changed", function() {
                    byId('i1').set('text', 'Foo');
                    expect(getItem('i1').textElement.dom).hasHTML('Foo');
                });

                describe("with iconCls: null", function() {
                    it("should remove hideIconCls when setting to empty", function() {
                        var item = getItem('i42');
                        expect(item.element).toHaveCls(item.hideIconCls);
                        expect(item.element).not.toHaveCls(item.withIconCls);

                        byId('i42').set('iconCls', '');
                        expect(item.element).not.toHaveCls(item.hideIconCls);
                        expect(item.element).not.toHaveCls(item.withIconCls);
                    });

                    it("should remove hideIconCls, add iconCls and add withIconCls when setting a class", function() {
                        var item = getItem('i42');
                        expect(item.element).toHaveCls(item.hideIconCls);
                        expect(item.element).not.toHaveCls(item.withIconCls);

                        byId('i42').set('iconCls', 'foo');
                        expect(item.element).not.toHaveCls(item.hideIconCls);
                        expect(item.element).toHaveCls(item.withIconCls);
                        expect(item.iconElement).toHaveCls('foo');
                    });
                });

                describe("with an empty iconCls", function() {
                    it("should add hideIconCls when setting to null", function() {
                        var item = getItem('i43');
                        expect(item.element).not.toHaveCls(item.hideIconCls);
                        expect(item.element).not.toHaveCls(item.withIconCls);

                        byId('i43').set('iconCls', null);
                        expect(item.element).toHaveCls(item.hideIconCls);
                        expect(item.element).not.toHaveCls(item.withIconCls);
                    });

                    it("should add withIconCls and set the icon when setting a class", function() {
                        var item = getItem('i43');
                        expect(item.element).not.toHaveCls(item.hideIconCls);
                        expect(item.element).not.toHaveCls(item.withIconCls);

                        byId('i43').set('iconCls', 'foo');
                        expect(item.element).not.toHaveCls(item.hideIconCls);
                        expect(item.element).toHaveCls(item.withIconCls);
                        expect(item.iconElement).toHaveCls('foo');
                    });
                });

                describe("with an iconCls specified", function() {
                    it("should remove withIconCls, clear iconCls and add hideIconCls when setting to null", function() {
                        var item = getItem('i41');
                        expect(item.element).not.toHaveCls(item.hideIconCls);
                        expect(item.element).toHaveCls(item.withIconCls);
                        expect(item.iconElement).toHaveCls('iconC');

                        byId('i41').set('iconCls', null);
                        expect(item.element).toHaveCls(item.hideIconCls);
                        expect(item.element).not.toHaveCls(item.withIconCls);
                        expect(item.iconElement).not.toHaveCls('iconC');
                    });

                    it("should remove withIconCls and clear iconCls when setting to empty", function() {
                        var item = getItem('i41');
                        expect(item.element).not.toHaveCls(item.hideIconCls);
                        expect(item.element).toHaveCls(item.withIconCls);
                        expect(item.iconElement).toHaveCls('iconC');

                        byId('i41').set('iconCls', '');
                        expect(item.element).not.toHaveCls(item.hideIconCls);
                        expect(item.element).not.toHaveCls(item.withIconCls);
                        expect(item.iconElement).not.toHaveCls('iconC');
                    });

                    it("should change the iconCls", function() {
                        var item = getItem('i1');

                        expect(item.element).toHaveCls(item.withIconCls);
                        byId('i1').set('iconCls', 'iconZ');
                        expect(item.iconElement).not.toHaveCls('iconA');
                        expect(item.iconElement).toHaveCls('iconZ');
                        expect(item.element).toHaveCls(item.withIconCls);
                    });
                });

                it("should set the cls and set the withIconCls when setting a iconCls", function() {
                    var item = getItem('i2'),
                        el = item.iconElement;

                    expect(item.element).not.toHaveCls(item.withIconCls);
                    byId('i2').set('iconCls', 'iconZ');
                    expect(el).toHaveCls('iconZ');
                    expect(item.element).toHaveCls(item.withIconCls);
                });

                it("should remove the cls and hide the iconElement when clearing a iconCls", function() {
                    var item = getItem('i1'),
                        el = item.iconElement;

                    expect(item.element).toHaveCls(item.withIconCls);
                    byId('i1').set('iconCls', '');
                    expect(el).not.toHaveCls('iconA');
                    expect(item.element).not.toHaveCls(item.withIconCls);
                });

                it("should change the class when modifying the iconCls", function() {
                    var item = getItem('i1'),
                        el = item.iconElement;

                    expect(item.element).toHaveCls(item.withIconCls);
                    byId('i1').set('iconCls', 'iconZ');
                    expect(el).not.toHaveCls('iconA');
                    expect(el).toHaveCls('iconZ');
                    expect(item.element).toHaveCls(item.withIconCls);
                });
            });
        });
    });

    // Disable these for now, they fail on device simulators
    xdescribe("expand/collapse via UI", function() {
        describe("with expanderOnly: false", function() {
            beforeEach(function() {
                sampleData[3].children[0].leaf = true;
                makeList({
                    expanderOnly: false
                });
            });

            it("should expand when clicking the expander of a collapsed item", function() {
                var item = getItem('i1');
                expect(item.isExpanded()).toBe(false);
                jasmine.fireMouseEvent(item.expanderElement.dom, 'click');
                expect(item.isExpanded()).toBe(true);
            });

            it("should collapse when clicking the expander of a expanded item", function() {
                var item = getItem('i4');
                expect(item.isExpanded()).toBe(true);
                jasmine.fireMouseEvent(item.expanderElement.dom, 'click');
                expect(item.isExpanded()).toBe(false);
            });

            it("should expand when clicking on the element of a collapsed item", function() {
                var item = getItem('i1');
                expect(item.isExpanded()).toBe(false);
                jasmine.fireMouseEvent(item.textElement.dom, 'click');
                expect(item.isExpanded()).toBe(true);
            });

            it("should collapse when clicking on the element of an expanded item", function() {
                var item = getItem('i4');
                expect(item.isExpanded()).toBe(true);
                jasmine.fireMouseEvent(item.textElement.dom, 'click');
                expect(item.isExpanded()).toBe(false);
            });

            it("should not collapse when clicking inside the itemContainer", function() {
                var item = getItem('i4');
                expect(item.isExpanded()).toBe(true);
                jasmine.fireMouseEvent(getItem('i41').textElement.dom, 'click');
                expect(item.isExpanded()).toBe(true);
            });
        });

        describe("with expanderOnly: true", function() {
            beforeEach(function() {
                makeList({
                    expanderOnly: true
                });
            });

            it("should expand when clicking the expander of a collapsed item", function() {
                var item = getItem('i1');
                expect(item.isExpanded()).toBe(false);
                jasmine.fireMouseEvent(item.expanderElement.dom, 'click');
                expect(item.isExpanded()).toBe(true);
            });

            it("should collapse when clicking the expander of an expanded item", function() {
                var item = getItem('i4');
                expect(item.isExpanded()).toBe(true);
                jasmine.fireMouseEvent(item.expanderElement.dom, 'click');
                expect(item.isExpanded()).toBe(false);
            });

            it("should not expand when clicking on the element of a collapsed item", function() {
                var item = getItem('i1');
                expect(item.isExpanded()).toBe(false);
                jasmine.fireMouseEvent(item.iconElement.dom, 'click');
                jasmine.fireMouseEvent(item.textElement.dom, 'click');
                jasmine.fireMouseEvent(item.element.dom, 'click');
                expect(item.isExpanded()).toBe(false);
            });

            it("should not collapse when clicking on the element of an expanded item", function() {
                var item = getItem('i4');
                expect(item.isExpanded()).toBe(true);
                jasmine.fireMouseEvent(item.iconElement.dom, 'click');
                jasmine.fireMouseEvent(item.textElement.dom, 'click');
                jasmine.fireMouseEvent(item.element.dom, 'click');
                expect(item.isExpanded()).toBe(true);
            });
        });
    });

});
