/*
This file is part of Ext JS 3.4

Copyright (c) 2011-2013 Sencha Inc

Contact:  http://www.sencha.com/contact

GNU General Public License Usage
This file may be used under the terms of the GNU General Public License version 3.0 as
published by the Free Software Foundation and appearing in the file LICENSE included in the
packaging of this file.

Please review the following information to ensure the GNU General Public License version 3.0
requirements will be met: http://www.gnu.org/copyleft/gpl.html.

If you are unsure which license is appropriate for your use, please contact the sales department
at http://www.sencha.com/contact.

Build date: 2013-04-03 15:07:25
*/
(function() {
    var suite  = Ext.test.session.getSuite('Ext.util.MixedCollection'),
        assert = Y.Assert;

    suite.add(new Y.Test.Case({
        name: 'constructor',

        setUp: function() {
            this.mc = new Ext.util.MixedCollection();
        },

        tearDown: function() {
            this.mc.clear();
        },

        //test that a default getKey implementation is set
        testHasDefaultGetKey: function() {
            var item1      = {id: 1, data: 'first item' },
                item2      = {id: 2, data: 'second item'};
            
            this.mc.add(item1);
            this.mc.add(item2);
            
            assert.areSame(item1, this.mc.get(1));
            assert.areSame(item2, this.mc.get(2));
        },

        //test that we can provide a getKey implementation
        testCanSetGetKey: function() {
            var collection = new Ext.util.MixedCollection(false, function(item) {
                return item.myKey;
            });
            
            var item1 = {myKey: 'a', data: 'first item' },
                item2 = {myKey: 'b', data: 'second item'};
            
            collection.add(item1);
            collection.add(item2);
            
            assert.areSame(item2, collection.get('b'));
            assert.areSame(item1, collection.get('a'));
        }
    }));
    
    suite.add(new Y.Test.Case({
        name: 'iterators',
        
        setUp: function() {
            this.mc = new Ext.util.MixedCollection();
            
            this.mc.addAll([
                {id: 1, name: 'first'},
                {id: 2, name: 'second'},
                {id: 3, name: 'third'}
            ]);
        },

        testEach: function() {
            var callCount = 0, callScope, total;
            
            this.mc.each(function(item, index, length) {
                //make sure that the function is called in the correct scope
                callScope = this;
                callCount ++;
                total = length;
            }, this);
            
            assert.areEqual(this, callScope);
            assert.areEqual(3, callCount);
            assert.areEqual(3, total);
        },
        
        testEachKey: function() {
            var callCount = 0, callScope;
            
            this.mc.eachKey(function(key, index, length) {
                //make sure that the function is called in the correct scope
                callScope = this;
                callCount ++;
            }, this);
            
            assert.areEqual(this, callScope);
            assert.areEqual(3, callCount);
        }
    }));
    
    suite.add(new Y.Test.Case({
        name: 'add and remove',
       
        setUp: function() {
            this.mc = new Ext.util.MixedCollection();
        },
       
        testAddAll: function() {
            var mc = this.mc;
            
            assert.areEqual(0, mc.length);
            
            mc.addAll([{id: 1}, {id: 2}, {id: 3}]);
            
            assert.areEqual(3, mc.length);
        },
        
        testAddAndClear: function() {
            var mc = this.mc;
            
            mc.add({id: 1});
            mc.add({id: 2});
            mc.add({id: 3});
            
            assert.areEqual(3, mc.length);
            
            mc.clear();
            assert.areEqual(0, mc.length);
        },
        
        testAddEventFired: function() {
            var mc    = this.mc,
                fired = false;
            
            mc.on('add', function() {fired = true;});
            
            mc.add({id: 1});
            assert.isTrue(fired);
        },
        
        testClearEventFired: function() {
            var mc    = this.mc,
                fired = false;
            
            mc.on('clear', function() {fired = true;}, this);
            mc.clear();
            
            assert.isTrue(fired);
        },
        
        testGetCount: function() {
            this.mc.add({id: 1});
            this.mc.add({id: 2});
            this.mc.add({id: 3});
            
            assert.areEqual(3, this.mc.getCount());
        },
        
        testRemove: function() {
            
        },
        
        testRemoveFiresEvent: function() {
            
        }
    }));
    
    suite.add(new Y.Test.Case({
        name: 'insert',
        
        setUp: function() {
            this.mc = new Ext.util.MixedCollection();
            
            this.mc.addAll([
                {id: 1, name: 'first'},
                {id: 2, name: 'second'},
                {id: 3, name: 'third'}
            ]);
        },
        
        doInsert: function() {
            this.mc.insert(1, {id: 4, name: 'fourth'});
        },
        
        testInsertsToCorrectLocation: function() {
            this.doInsert();
            
            assert.areEqual(4, this.mc.itemAt(1).id);
        },
        
        testOtherItemsPreserved: function() {
            var prevCount = this.mc.getCount();
            
            this.doInsert();
            assert.areEqual(prevCount + 1, this.mc.getCount());
        },
        
        testFiresAddEvent: function() {
            var fired = false;
            
            this.mc.on('add', function() { fired = true; });
            this.doInsert();
            
            assert.isTrue(fired);
        }
    }));
    
    suite.add(new Y.Test.Case({
        name: 'replace',
        
        setUp: function() {
            this.mc = new Ext.util.MixedCollection();
            
            this.mc.addAll([
                {id: 1, name: 'first'},
                {id: 2, name: 'second'},
                {id: 3, name: 'third'}
            ]);
        },
        
        doReplace: function() {
            this.mc.replace(2, {id: 4, name: 'fourth'});
        },
        
        testReplacesCorrectItem: function() {
            this.doReplace();
            assert.areEqual("fourth", this.mc.itemAt(1).name);
        },
        
        testPreviousItemRemoved: function() {
            var prevCount = this.mc.getCount();
            
            this.doReplace();
            assert.areEqual(prevCount, this.mc.getCount());
        },
        
        testReplaceEventFired: function() {
            var fired = false;
            
            this.mc.on('replace', function() { fired = true; });
            this.doReplace();
            
            assert.isTrue(fired);
        }
    }));
    
    suite.add(new Y.Test.Case({
        name: 'clone',
        
        setUp: function() {
            this.mc = new Ext.util.MixedCollection();
            
            this.mc.addAll([
                {id: 1, name: 'first'},
                {id: 2, name: 'second'},
                {id: 3, name: 'third'}
            ]);
        },
        
        //test that a shallow clone is completed correctly
        testClone: function() {
            var newMC = this.mc.clone();
            
            assert.areEqual(3, newMC.getCount());
            
            Ext.each([1, 2, 3], function(id) {
              assert.areEqual(this.mc.get(id).id, newMC.get(id).id);
            }, this);
        }
    }));
    
    suite.add(new Y.Test.Case({
        name: 'getting items',
        
        setUp: function() {
            this.mc = new Ext.util.MixedCollection();
            this.item1 = {id: 1, name: 'first'};
            
            this.mc.addAll([
                this.item1,
                {id: 2, name: 'second'},
                {id: 3, name: 'third'}
            ]);
        },
        
        testFirst: function() {
            assert.areEqual(1, this.mc.first().id);
        },
        
        testLast: function() {
            assert.areEqual(3, this.mc.last().id);
        },
        
        testGet: function() {
            assert.areEqual(2, this.mc.get(2).id);
        },
        
        testGetKey: function() {
            assert.areEqual(1, this.mc.getKey(this.item1));
        },
        
        //should return items in the given range
        testGetRange: function() {
            var items = this.mc.getRange(1, 2);
            
            assert.areEqual(2, items.length);
            assert.areEqual(2, items[0].id);
            assert.areEqual(3, items[1].id);
        },
        
        //should get all items
        testGetRangeWithNoArguments: function() {
            var items = this.mc.getRange();
            
            assert.areEqual(3, items.length);
        },
        
        //should get all items after the provided start index
        testGetRangeWithNoEnd: function() {
            var items = this.mc.getRange(1);
            
            assert.areEqual(2, items.length);
        },
        
        testIndexOf: function() {
            assert.areEqual(0, this.mc.indexOf(this.item1));
        },
        
        testIndexOfKey: function() {
            assert.areEqual(2, this.mc.indexOfKey(3));
        },
        
        testKey: function() {
            assert.areEqual(3, this.mc.key(3).id);
        },
        
        testItemByIndex: function() {
            this.mc.add({id: 'a', name: 'another item'});
            this.mc.add({id: 'b', name: 'yet another item'});
            
            assert.areEqual('b', this.mc.item(4).id);
        },
        
        //key should take priority over index
        testItemByKey: function() {
            this.mc.add({id: 'a', name: 'another item'});
            
            assert.areEqual('a', this.mc.item('a').id);
        },
        
        testItemAt: function() {
            assert.areEqual(3, this.mc.itemAt(2).id);
        }
    }));
    
    suite.add(new Y.Test.Case({
        name: 'find functions',
        
        setUp: function() {
            this.mc = new Ext.util.MixedCollection();
            
            this.mc.addAll([
                {id: 1, name: 'first'},
                {id: 2, name: 'second'},
                {id: 3, name: 'third'}
            ]);
        },
        
        testFind: function() {
            var matched = this.mc.find(function(item) {
                return item.name == 'third';
            });
            
            assert.areEqual('third', matched.name);
        },
        
        testFindIndex: function() {
            var matched = this.mc.findIndex('name', 'third');
            
            assert.areEqual(2, matched);
        },
        
        testFindIndexBy: function() {
            var matched = this.mc.findIndexBy(function(item) {
                return item.name == 'second';
            });
            
            assert.areEqual(1, matched);
        }
    }));
    
    suite.add(new Y.Test.Case({
        name: 'contains',
        
        setUp: function() {
            this.mc = new Ext.util.MixedCollection();
            this.item = {id: 1, name: 'first'};
            
            this.mc.addAll([
                this.item,
                {id: 2, name: 'second'},
                {id: 3, name: 'third'}
            ]);
        },
        
        tearDown: function() {
            delete this.item;
        },
        
        testContains: function() {
            assert.isTrue(this.mc.contains(this.item));
        },
        
        testDoesNotContain: function() {
            assert.isFalse(this.mc.contains({some: 'object'}));
        },
        
        testContainsKey: function() {
            assert.isTrue(this.mc.containsKey(1));
        },
        
        testDoesNotContainKey: function() {
            assert.isFalse(this.mc.containsKey('abc'));
        }
    }));
    
    suite.add(new Y.Test.Case({
        name: 'single sorting',
        
        setUp: function() {
            this.mc = new Ext.util.MixedCollection(false, function(item) {
                return item['code'];
            });
            
            this.mc.addAll([
                {id: 1, name: 'first',  code: 'C', modifier: 10},
                {id: 2, name: 'second', code: 'A', modifier: 100},
                {id: 3, name: 'third',  code: 'B', modifier: 5}
            ]);
        },
        
        testKeySort: function() {
            var mc = this.mc;
            mc.keySort();
            
            assert.areEqual('A', mc.itemAt(0).code);
            assert.areEqual('B', mc.itemAt(1).code);
            assert.areEqual('C', mc.itemAt(2).code);
        },
        
        testDirectionalKeySort: function() {
            var mc = this.mc;
            mc.keySort('DESC');
            
            assert.areEqual('C', mc.itemAt(0).code);
            assert.areEqual('B', mc.itemAt(1).code);
            assert.areEqual('A', mc.itemAt(2).code);
        },
        
        testSort: function() {
            var mc = new Ext.util.MixedCollection();
            mc.addAll(3, 1, 4, 2);
            mc.sort();
            
            assert.areEqual(1, mc.itemAt(0));
            assert.areEqual(2, mc.itemAt(1));
            assert.areEqual(3, mc.itemAt(2));
            assert.areEqual(4, mc.itemAt(3));
        },
        
        testDirectionalSort: function() {
            
        },
        
        testSortWithComparator: function() {
            var mc = this.mc;
            mc.sort('ASC', function(a, b) {
                return (a.id * a.modifier) - (b.id * b.modifier);
            });
            
            assert.areEqual('C', mc.itemAt(0).code);
            assert.areEqual('B', mc.itemAt(1).code);
            assert.areEqual('A', mc.itemAt(2).code);
        },
        
        testDirectionalSortWithComparator: function() {
            var mc = this.mc;
            mc.sort('DESC', function(a, b) {
                return (a.id * a.modifier) - (b.id * b.modifier);
            });
            
            assert.areEqual('A', mc.itemAt(0).code);
            assert.areEqual('B', mc.itemAt(1).code);
            assert.areEqual('C', mc.itemAt(2).code);
        },
        
        testSortEventFired: function() {
            var fired = false;
            
            this.mc.on('sort', function() { fired = true; });
            this.mc.sort('name');
            
            assert.isTrue(fired);
        }
    }));
    
    suite.add(new Y.Test.Case({
        name: 'reordering',
        
        setUp: function() {
            this.mc = new Ext.util.MixedCollection(false, function(item) {
                return item['code'];
            });
            
            this.mc.addAll([
                {id: 1, name: 'first',  code: 'C', modifier: 10},
                {id: 2, name: 'second', code: 'A', modifier: 100},
                {id: 3, name: 'third',  code: 'B', modifier: 5}
            ]);
        },
        
        testReordering: function() {
            var mc = this.mc;
            
            mc.reorder({
                1: 2,
                2: 0
            });
            
            assert.areEqual('B', mc.itemAt(0).code);
            assert.areEqual('C', mc.itemAt(1).code);
            assert.areEqual('A', mc.itemAt(2).code);
        },
        
        testSortEventFired: function() {
            var wasFired = false,
                mc       = this.mc;
            
            mc.on('sort', function() {
                wasFired = true;
            }, this);
            
            mc.reorder({
                1: 2,
                2: 0
            });
            
            assert.isTrue(wasFired);
        }
    }));
})();