Ext.namespace('Abacus');
Abacus.JsonStore = Ext.extend(Ext.data.Store, {
    // Prototype Defaults, can be overridden by user's config object
    constructor: function(config){
        this.addEvents(
                /** @event invalid
                 *  Indicates that a record has not been saved as it was marked invalid
                 * @param {Abacus.JsonStore} store The store (i.e. this)
                 * @param {Ext.data.Record} record The record that was marked invalid
                 * @param {Number} index The index of the record in this store (-1 if not found - i.e. outside of the loaded page.  This should not happen normally though)
                 * @param {Object} errors An object keyed by field and containing the error description 
                 * */
                'invalid'
                );
        Abacus.JsonStore.superclass.constructor.call(this, Ext.apply({},config,{
            proxy: new Abacus.HttpProxy({url: config.url,listeners:{
              /* TODO Automatically request the meta data if not configured */
              beforeload:function(t,params){params.format='ext_json'; params.include_meta='1'},
              beforewrite:function(t,action,record,options,arg){options.format='ext_json'}
            }}),
            reader: new Abacus.JsonReader(),
            // turn on remote sorting
            remoteSort: true,
            sortInfo: {field: 'id', direction: 'ASC'}
            ,writer: new Ext.data.JsonWriter()
            ,restful:true

        }));
        this.on('metachange',function(store,meta){if(store.writer){store.writer.meta.root=store.reader.meta.root}})
        /* If the store is trying to submit any data for the associations, stop it here */
        this.proxy.on('beforewrite',function(proxy,action,record,options,args){
            var obj=Ext.util.JSON.decode(options[this.reader.meta.root]);
            for(var prop in obj){
                var match;
                if(match=prop.match(/(.*)\.(.*)/)){
                    /* If we have a property such as profile.field_1, then we should make sure that the profile object has field_1 set to the same value */
                    var rec_obj=record.get(match[1]);
                    if(rec_obj){
                        rec_obj[match[2]]=record.get(match[0]);
                        
                    }
                    var nested=match[1]+'_attributes';
                    if(!obj[nested]) obj[nested]={};
                    obj[nested][match[2]]=record.get(match[0]);
                    if(!obj[nested]['id']){
                        var nested_id=record.get(match[1]+".id");
                        if(nested_id){
                            obj[nested]['id']=nested_id;
                        }
                    }
                    delete obj[prop];
                }
            }
            options[this.reader.meta.root]=Ext.util.JSON.encode(obj);
            return true;
        },this);

        this.proxy.on('exception',function(proxy,type,action,options,response,arg){
            //We will have an errors hash in the response.raw.
            //We need to copy this into the data of the response where it will be handled by the updateErrors method of the reader (custom)
            if(type=='remote' && response.raw){
                //arg is the record
                this.reader.updateErrors(arg,response.raw);
                var index=this.indexOf(arg);
                this.fireEvent('invalid',this,arg,index,response.raw);
            }
        },this);

    }






});
Abacus.JsonReader = Ext.extend(Ext.data.JsonReader,{
    updateErrors:function(rs,data){
        Ext.each(data.messages,function(msg){
            rs.markInvalid(msg[0],msg[1]);
        },this);
    }
});
Abacus.HttpProxy = Ext.extend(Ext.data.HttpProxy,{
    onWrite:function(action, o, response, rs){
        var json=Ext.util.JSON.decode(response.responseText);
        if(json.success){
            Abacus.HttpProxy.superclass.onWrite.apply(this,arguments);
        }else{
            var res = new Ext.data.Response({action:action,data:[],message:'',raw:Ext.util.JSON.decode(response.responseText),records:rs,success:false}); 
            this.fireEvent('exception', this, 'remote', action, o, res, rs); 
        }

    }
});
Ext.override(Ext.data.Record,{
    markInvalid:function(field,message){
        if(!this.errors) this.errors={};
        this.errors[field]=message;
    }
});


// register xtype to allow for lazy initialization
Ext.reg('abacusjsonstore', Abacus.JsonStore);
