/*
 * Zefy-Ext
 *
 * Written by Joshua M. Thompson <jmt@zefy.org>
 */

/*jslint browser: true, devel: true, eqeqeq: false, onevar: false, plusplus: false, white: false */
/*global Zefy: true, Ext: true */

Zefy = {
    classes: [ ],

    format: '.json',

    createProxy: function(rClass, options) {
        var c = this.getClassInfo(rClass);
        if (!c) {
            return;
        }

        var config = { parent: '' };
        var url;

        if (options) {
            Ext.apply(config, options);
        }

        Ext.applyIf(config, {
            url: config.parent + c.controller + this.format,
            restful: true
        });

        return new Ext.data.HttpProxy(config);
    },

    createReader: function(rClass, options) {
        var c = this.getClassInfo(rClass);
        if (!c) {
            return;
        }

        var config = {};

        if (options) {
            Ext.apply(config, options);
        }

        Ext.applyIf(config, {
            root: 'data',
            idProperty: c.pk,
            messageProperty: 'message',
            totalProperty: 'total'
        });

        return new Ext.data.JsonReader(config, rClass);
    },

    createStore: function(rClass, options) {
        var c = this.getClassInfo(rClass);
        if (!c) {
            return;
        }

        var config = {};

        if (options) {
            Ext.apply(config, options);
        }

        Ext.applyIf(config, {
            proxy: this.createProxy(rClass, config.proxyOptions),
            reader: c.reader,
            autoLoad: false,
            autoSave: true,
            restful: true,
            remoteSort: false,
            writeable: true
        });

        if (config.writeable) {
            Ext.applyIf(config, { writer: this.createWriter(rClass) });
        }

/*
        if (config.groupField) {
            Ext.applyIf(config, { sortInfo: { field: config.groupField, direction: 'ASC' } });
        }
*/

        if (config.grouping) {
            delete config.grouping;

            return new Ext.data.GroupingStore(config);
        }
        else {
            return new Ext.data.Store(config);
        }
    },

    createWriter: function(rClass, options) {
        var c = this.getClassInfo(rClass);
        if (!c) {
            return;
        }

        var config = {};

        if (options) {
            Ext.apply(config, options);
        }

        Ext.applyIf(config, { encode: false, encodeDelete: false });

        var writer = new Ext.data.JsonWriter(config);
        writer.meta = c.reader.meta; // technically a private api, as of ExtJS 3.2.1, but necessary

        return writer;
    },

    getClassInfo: function(rClass) {
        for (var i = 0 ; i < this.classes.length ; i++) {
            if (this.classes[i].rclass === rClass) {
                return this.classes[i];
            }
        }
    },

    getBaseURL: function(rClass, record) {
        var c = this.getClassInfo(rClass);
        if (!c) {
            return;
        }

        return c.controller + '/' + record.id;
    },

    deleteRecord: function(rClass, record, callback, scope, options) {
        var c = this.getClassInfo(rClass);
        if (!c) {
            return;
        }

        var params = {};

        c.writer.apply(params, {}, 'destroy', record);
        c.proxy.request('destroy', record, params, c.reader, callback, scope, options);
    },

    loadRecord: function(rClass, id, callback, scope, options) {
        var c = this.getClassInfo(rClass);
        if (!c) {
            return;
        }

        var record = new rClass(null, id);

        c.proxy.request('read', record, {}, c.reader, callback, scope, options);
    },

    saveRecord: function(rClass, record, callback, scope, options) {
        var c = this.getClassInfo(rClass);
        if (!c) {
            return;
        }

        var params = {};
        var action;

        if (record.phantom) {
            action = 'create';
        }
        else {
            action = 'update';
        }

        c.writer.apply(params, {}, action, record);
        c.proxy.request(action, record, params, c.reader, callback, scope, options);
    },

    registerClass: function(rClass, options) {
        var c = this.getClassInfo(rClass);

        if (c) {
            c.apply(options);
        }
        else {
            c = { rclass: rClass };

            Ext.apply(c, options);

            this.classes.push(c);
        }

        // createWriter actually needs a valid reader registered,
        // so these must be done separately and in this order

        Ext.applyIf(c, {
            proxy: this.createProxy(rClass),
            reader: this.createReader(rClass)
        });
        Ext.applyIf(c, {
            writer: this.createWriter(rClass)
        });

        rClass.zfCreateProxy  = Zefy.createProxy.createDelegate(this, [ rClass ], 0);
        rClass.zfCreateReader = Zefy.createReader.createDelegate(this, [ rClass ], 0);
        rClass.zfCreateStore  = Zefy.createStore.createDelegate(this, [ rClass ], 0);
        rClass.zfCreateWriter = Zefy.createWriter.createDelegate(this, [ rClass ], 0);
        rClass.zfGetBaseURL   = Zefy.getBaseURL.createDelegate(this, [ rClass ], 0);
        rClass.zfLoadRecord   = Zefy.loadRecord.createDelegate(this, [ rClass ], 0);
        rClass.zfDeleteRecord = Zefy.deleteRecord.createDelegate(this, [ rClass ], 0);
        rClass.zfSaveRecord   = Zefy.saveRecord.createDelegate(this, [ rClass ], 0);

        return c;
    }
};

