/**
 * This class is used to store data on the client in a specified `storage` (either 'local'
 * or 'session'). Unlike the {@link Ext.data.proxy.LocalStorage localStorage proxy}, this
 * store uses a single `storageKey` to hold the entire contents of the store. This helps
 * reduce key overhead but also requires that all records and field be saved for any change.
 */
Ext.define('Ext.data.ClientStore', {
    extend: 'Ext.data.Store',
    alias: 'store.clientstorage',

    requires: [
        'Ext.data.proxy.Memory'
    ],

    config: {
        /**
         * @cfg {"local"/"session"} storage
         * Specify 'local' to use `localStorage` and 'session' to use `sessionStorage`.
         */
        storage: 'local',

        /**
         * @cfg {String} storageKey (required)
         * The key to use for saving the content of this store.
         */
        storageKey: null
    },

    trackRemoved: false,

    proxy: {
        type: 'memory',
        clearOnRead: true
    },

    sync: function(options) {
        var me = this,
            key = me._getKey(),
            storage = me.getStorage(),
            source = me.getDataSource(),
            proxy = me.getProxy(),
            writer = proxy.getWriter(),
            writeAll = writer.getWriteAllFields(),
            data = [];

        try {
            me.suspendAutoSync();
            writer.setWriteAllFields(true);

            source.each(function(rec) {
                if (rec.phantom) {
                    rec.setId(me.nextId());
                }

                data.push(writer.getRecordData(rec));
                rec.commit();
            });

            if (data.length) {
                data = JSON.stringify(data);
                data = storage.setItem(key, data);
            }
            else {
                storage.removeItem(key);
            }

            if (options && options.success) {
                Ext.callback(options.success, options.scope || proxy, [null, options]);
            }
        }
        catch (e) {
            if (options && options.failure) {
                Ext.callback(options.failure, options.scope || proxy, [null, options]);
            }
        }
        finally {
            me.resumeAutoSync();
            writer.setWriteAllFields(writeAll);
        }

        if (options && options.callback) {
            Ext.callback(options.callback, options.scope || proxy, [null, options]);
        }

        return me;
    },

    applyStorage: function(storage) {
        var ret = Ext.global[storage + 'Storage'];

        //<debug>
        if (!ret || !ret.getItem || !ret.setItem) {
            Ext.raise('Invalid storage config "' + storage + '"; ' +
                'expected "local" or "session"');
        }
        //</debug>

        return ret;
    },

    updateProxy: function(proxy, oldProxy) {
        var me = this,
            key = me._getKey(),
            storage = me.getStorage(),
            data;

        me.callParent([ proxy, oldProxy ]);

        data = storage.getItem(key);

        if (data) {
            proxy.setData(JSON.parse(data));
        }
    },

    privates: {
        _getKey: function() {
            var key = this.getStorageKey();

            //<debug>
            if (!key) {
                Ext.raise('ClientStore requires a storageKey');
            }
            //</debug>

            return key;
        },

        nextId: function() {
            var source = this.getDataSource(),
                id = 1;

            while (source.containsKey(id)) {
                ++id;
            }

            return id;
        }
    }
});