/*!
 * Ext JS Library 3.4.0
 * Copyright(c) 2006-2011 Sencha Inc.
 * licensing@sencha.com
 * http://www.sencha.com/license
 */
/**
 * Tests Ext.data.Store functionality
 * @author Ed Spencer
 */
(function() {
    var suite  = Ext.test.session.getSuite('Ext.data.Store'),
        assert = Y.Assert;

    //a shared setup function used by several of the suites
    var defaultSetup = function() {
        this.store = new Ext.data.Store({
            proxy : new Ext.data.MemoryProxy({}),
            reader: new Ext.data.ArrayReader({}, [
                {name: 'name',      type: 'string'},
                {name: 'email',     type: 'string'},
                {name: 'greatness', type: 'int'},
                {name: 'group',     type: 'string'},
                {name: 'old',       type: 'boolean'}
            ]),
            storeId: 'myStore',
            remoteSort: false
        });

        this.store.loadData([
            ['Ed Spencer',   'ed@extjs.com',    100, 'code',  false],
            ['Abe Elias',    'abe@extjs.com',   70,  'admin', false],
            ['Aaron Conran', 'aaron@extjs.com', 5,   'admin', true],
            ['Tommy Maintz', 'tommy@extjs.com', -15, 'code',  true]
        ]);
    };

    suite.add(new Y.Test.Case({
        name: 'local single sorting',

        setUp: defaultSetup,

        testSetDefaultSort: function() {
            this.store.setDefaultSort('name', 'DESC');

            var store    = this.store,
                sortInfo = store.sortInfo;

            assert.areEqual('name', sortInfo.field);
            assert.areEqual('DESC', sortInfo.direction);
            assert.areEqual('DESC', store.sortToggle['name']);
        },

        testSetDefaultSortDefaultToASC: function() {
            this.store.setDefaultSort('email');

            var store    = this.store,
                sortInfo = store.sortInfo;

            assert.areEqual('email', sortInfo.field);
            assert.areEqual('ASC', sortInfo['direction']);
            assert.areEqual('ASC', store.sortToggle['email']);
        },

        testSortByField: function() {
            var store = this.store;

            store.sort('name', 'ASC');
            assert.areEqual('Aaron Conran', store.getAt(0).get('name'));
            assert.areEqual('Abe Elias',    store.getAt(1).get('name'));
            assert.areEqual('Ed Spencer',   store.getAt(2).get('name'));
            assert.areEqual('Tommy Maintz', store.getAt(3).get('name'));
        },

        testToggling: function() {
            var store = this.store;

            store.sort('name', 'ASC');

            //second call to sort toggles the direction
            store.sort('name');

            assert.areEqual('Aaron Conran', store.getAt(3).get('name'));
            assert.areEqual('Abe Elias',    store.getAt(2).get('name'));
            assert.areEqual('Ed Spencer',   store.getAt(1).get('name'));
            assert.areEqual('Tommy Maintz', store.getAt(0).get('name'));
        },

        testSetsHasMultiSort: function() {
            this.store.sort('name', 'ASC');

            assert.isFalse(this.store.hasMultiSort);
        },

        testEventFired: function() {
            var executed = false,
                store    = this.store;

            store.on('datachanged', function() {
                executed = true;
            }, this);

            store.sort('name');
            assert.isTrue(executed);
        },

        testSavesSortInfo: function() {
            var store = this.store;

            store.sort('name', 'DESC');

            assert.areEqual('name', store.sortInfo.field);
            assert.areEqual('DESC', store.sortInfo.direction);
        },

        //if we tell store to sort on a non-existent field it should return false and do nothing
        testInvalidFieldIgnored: function() {
            var store = this.store;

            //first we'll sort by name to give some reference sorting
            store.sort('name', 'ASC');

            assert.isFalse(store.sort('someUnknownField'));

            //make sure the original sorting was preserved
            assert.areEqual('Aaron Conran', store.getAt(0).get('name'));
            assert.areEqual('Abe Elias',    store.getAt(1).get('name'));
            assert.areEqual('Ed Spencer',   store.getAt(2).get('name'));
            assert.areEqual('Tommy Maintz', store.getAt(3).get('name'));
        }
    }));

    suite.add(new Y.Test.Case({
        name: 'local multiple sorting',

        setUp: function() {
            defaultSetup.call(this);

            this.sorters = [
                {
                    field    : 'group',
                    direction: 'ASC'
                },
                {
                    field    : 'old',
                    direction: 'DESC'
                }
            ];
        },

        testSetsHasMultiSort: function() {
            this.store.sort(this.sorters);

            assert.isTrue(this.store.hasMultiSort);
        },

        testMultipleSorters: function() {
            var store   = this.store,
                sorters = this.sorters;

            store.sort(sorters);

            assert.areEqual('Aaron Conran', store.getAt(0).get('name'));
            assert.areEqual('Abe Elias',    store.getAt(1).get('name'));
            assert.areEqual('Tommy Maintz', store.getAt(2).get('name'));
            assert.areEqual('Ed Spencer',   store.getAt(3).get('name'));
        }

        // testMultipleSorterToggling: function() {
        //     var store   = this.store,
        //         sorters = this.sorters;
        //
        //     //first we'll sort to give some reference sorting
        //     store.sort(sorters, "ASC");
        //
        //     //second call to sort toggles direction
        //     store.sort(sorters);
        //
        //     assert.areEqual('Aaron Conran', store.getAt(3).get('name'));
        //     assert.areEqual('Abe Elias',    store.getAt(2).get('name'));
        //     assert.areEqual('Tommy Maintz', store.getAt(1).get('name'));
        //     assert.areEqual('Ed Spencer',   store.getAt(0).get('name'));
        // }
    }));

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

        setUp: defaultSetup,

        testFilterByField: function() {
            var store = this.store;

            store.filter('group', 'code');
            assert.areEqual(2, store.getCount());
        },

        testFilterByFieldAnyMatch: function() {
            var store = this.store;

            store.filter('email', 'extjs', true);
            assert.areEqual(4, store.getCount());
        },

        testFilterByFieldCaseSensitive: function() {
            var store = this.store;

            store.filter('group', 'Code', false, true);
            assert.areEqual(0, store.getCount());
        },

        testFilterByFieldExactMatch: function() {
            var store = this.store;

            store.filter('email', 'aaron', false, false, true);
            assert.areEqual(0, store.getCount());
        },

        testClearFilter: function() {
            var store    = this.store,
                executed = false;

            store.on('datachanged', function() {
                executed = true;
            }, this);

            store.filter('group', 'code');
            assert.areEqual(2, store.getCount());

            store.clearFilter();
            assert.areEqual(4, store.getCount());

            assert.isTrue(executed);
        },

        testSuppressClearFilterEvent: function() {
            var store    = this.store,
                executed = false;

            store.filter('group', 'email');
            store.clearFilter(true);

            store.on('datachanged', function() {
                executed = true;
            }, this);
            assert.isFalse(executed);
        },

        testIsFiltered: function() {
            var store = this.store;

            assert.isFalse(store.isFiltered());
            store.filter('group', 'code');
            assert.isTrue(store.isFiltered());
        },

        testFilterByFunction: function() {
            var store = this.store,
                execScope,
                executed;

            store.on('datachanged', function() {
                executed = true;
            }, this);

            var filterFn = function(item) {
                execScope = this;

                return item.get('greatness') > 50;
            };

            store.filterBy(filterFn, this);
            assert.areEqual(this, execScope);
            assert.areEqual(2, store.getCount());
            assert.isTrue(executed);
        }
    }));

    suite.add(new Y.Test.Case({
        name : 'filtering more than once',
        setUp: defaultSetup,

        testFirstFilterIsCleared: function() {
            var store = this.store;

            store.filter('group', 'code');
            assert.areEqual(2, store.getCount());

            store.filter('old', false);

            //if filter had not been reset first, count would be 1
            assert.areEqual(2, store.getCount());
        }
    }));

    suite.add(new Y.Test.Case({
        name : 'multiple filters',
        setUp: function() {
            defaultSetup.call(this);

            this.filters = [
                {
                    property: 'group',
                    value   : 'code'
                },
                {
                    property: 'old',
                    value   : true
                }
            ];
        },

        testMultipleBasicFilters: function() {
            this.store.filter(this.filters);

            //applying the filter set above shoule yield one result
            assert.areEqual(1, this.store.getCount());
            assert.areEqual('Tommy Maintz', this.store.data.first().get('name'));
        },

        testMultiFiltersFiresDataChanged: function() {
            var executed = false;

            this.store.on('datachanged', function() {
                executed = true;
            }, this);

            this.store.filter(this.filters);

            assert.isTrue(executed);
        },

        //tests that the anyMatch and caseSensitive defaults are correctly applied
        testMultiFilterDefaults: function() {
            //PENDING
        },

        //tests a single custom filter
        testCustomFilter: function() {
            var execScope;

            //tests that the passed filter function is called
            //tests that the filter is called in the right scope
            this.store.filter({
                fn: function(record) {
                    execScope = this;
                    return record.get('group') == 'admin' && record.get('old') === true;
                },
                scope: this
            });

            assert.areEqual(this, execScope);
            assert.areEqual(1, this.store.getCount());
            assert.areEqual('Aaron Conran', this.store.data.first().get('name'));
        },

        //tests multiple filters where we pass in custom matcher functions
        testMultiCustomFilters: function() {
            this.store.filter([
                {
                    fn: function(record) {
                        return record.get('group') == 'admin';
                    }
                },
                {
                    fn: function(record) {
                        return record.get('old') === false;
                    }
                }
            ]);

            assert.areEqual(1, this.store.getCount());
            assert.areEqual('Abe Elias', this.store.data.first().get('name'));
        },

        testBasicAndCustomFilters: function() {
            //should return a single result - Ed Spencer
            this.store.filter([
                {
                    fn: function(record) {
                        return record.get('old') === false;
                    }
                },
                {
                    property: 'group',
                    value   : 'code'
                }
            ]);

            assert.areEqual(1, this.store.getCount());
            assert.areEqual('Ed Spencer', this.store.data.first().get('name'));
        },

        testClearMultipleFilters: function() {
            this.store.filter(this.filters);
            assert.areEqual(1, this.store.getCount());

            //make sure that clearing multiple filters is still correct
            this.store.clearFilter();
            assert.areEqual(4, this.store.getCount());
        }
    }));

    suite.add(new Y.Test.Case({
        name: 'inserting and removing',

        testInsert: function() {
            //PENDING
        },

        testInsertFiresAddEvent: function() {
            //PENDING
        },

        testRemove: function() {
            //PENDING
        },

        testRemoveAll: function() {
            //PENDING
        },

        testRemoveAt: function() {
            //PENDING
        }
    }));

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

        setUp: defaultSetup,

        //we hijack Ext.StoreMgr.unregister temporarily and then set it back in this test case
        testUnregistersFromStore: function() {
            var executed   = false,
                arg        = undefined,
                unregister = Ext.StoreMgr.unregister;

            Ext.StoreMgr.unregister = function(store) {
                executed = true;
                arg = store;
            };

            this.store.destroy();

            assert.isTrue(executed);
            assert.areEqual(this.store, arg);

            Ext.StoreMgr.unregister = unregister;
        },

        testClearsData: function() {
            var executed = false;
            this.store.clearData = function() {
                executed = true;
            };

            this.store.destroy();
            assert.isTrue(executed);
        },

        testDestroysProxy: function() {
            var executed = false,
                arg      = undefined,
                proxy    = this.store.proxy,
                destroy  = Ext.destroy;

            Ext.destroy = function(store) {
                executed = true;
                arg = store;
            };

            this.store.destroy();

            assert.isTrue(executed);
            assert.areEqual(proxy, arg);

            Ext.destroy = destroy;
        },

        testUnsetsReferences: function() {
            this.store.destroy();

            assert.isNull(this.store.reader);
            assert.isNull(this.store.writer);
            assert.isNull(this.store.data);
        },

        testIsDestroyed: function() {
            assert.isFalse(this.store.isDestroyed);

            this.store.destroy();

            assert.isTrue(this.store.isDestroyed);
        }
    }));

    suite.add(new Y.Test.Case({
        name: 'counting and iterators',

        setUp: defaultSetup,

        testGetCount: function() {
            assert.areEqual(4, this.store.getCount());
        },

        testGetTotalCount: function() {
            //PENDING - need a fake remote data set test with paging
        },

        testEach: function() {
            var count = 0,
                callScope;

            this.store.each(function() {
                callScope = this;
                count ++;
            }, this);

            assert.areEqual(4, count);
            assert.areEqual(this, callScope);
        },

        testSum: function() {
            var sum = this.store.sum('greatness');

            assert.areEqual(160, sum);
        },

        testSumWithStartAndEnd: function() {
            var sum = this.store.sum('greatness', 1, 3);

            assert.areEqual(60, sum);
        },

        //a normal collect test - check that we're pulling the right values out of the store
        testCollect: function() {
            var values = this.store.collect('name');

            assert.areEqual(4, values.length);
            assert.areNotEqual(-1, values.indexOf("Ed Spencer"));
            assert.areNotEqual(-1, values.indexOf("Abe Elias"));
            assert.areNotEqual(-1, values.indexOf("Aaron Conran"));
            assert.areNotEqual(-1, values.indexOf("Tommy Maintz"));
        },

        //checks that all collected values are unique
        testCollectIsUnique: function() {
            var values = this.store.collect('group');

            assert.areEqual(2, values.length);
            assert.areNotEqual(-1, values.indexOf("code"));
            assert.areNotEqual(-1, values.indexOf("admin"));
        }
    }));

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

        testCommitChanges: function() {
            //PENDING
        },

        testRejectChanges: function() {
            //PENDING
        },

        testAfterCommit: function() {
            //PENDING
        },

        testAfterReject: function() {
            //PENDING
        }
    }));

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

        testGetModifiedRecords: function() {
            //PENDING
        }
    }));

    suite.add(new Y.Test.Case({
        name: 'loading'
    }));
})();
