Ext.ns('FW','FW.DataStore');
FW.DataStore=function(data){
    this.data_store = data || {};
    this.addEvents('datachanged','cleared','removed','added','page_unload');
    this.idx_re = /\[(\w+)\]/;
    FW.DataStore.superclass.constructor.call(this);
}
Ext.extend(FW.DataStore, Ext.util.Observable);
CURRENT_PROTO=FW.DataStore.prototype;

//static methods
/**
    Converts the given argument, which must be an array of hashes, to Ext.dataStore
    @param {Array} data The Array to be converted
    @params {Array} Record Definition Objects.
    @return  {Ext.data.Store}
*/
FW.DataStore.to_store=function(array_data, rec_defs) {
    if(!Ext.isArray(array_data))
        throw "First Argument to FW.DataStore.to_store must be an array ";
    if(rec_defs && !Ext.isArray(rec_defs))
        throw "Second Argument to FW.DataStore.to_store must be an array ";
    if(!rec_defs) {
        rec_defs = [];
        var one_rec = array_data[0];
        if(Ext.type(one_rec) != 'object')
            throw 'array_data must consist of Hashes';
        for(var k in one_rec) {
            var def = {name: k};
            // try to guess the data type
            var v=one_rec[k];
            var type = Ext.type(v);
            switch(type) {
                case 'number':
                case 'boolean':
                    break;
                case 'string':
                    if(Ext.isDate(v))
                        type = 'date';
                default:
                    type = 'string';
            }
            def.type = type;
            rec_defs.push(def);
        }
    }

    var data_reader = new Ext.data.JsonReader({
                                      totalProperty: 'total_rows',
                                      id: 'id',
                                      root:'data'
                                 },
                                 rec_defs
    );
    return new Ext.data.Store({
        reader: data_reader,
        proxy: new Ext.data.MemoryProxy({data: array_data, total_rows: array_data.length})
    });
}
CURRENT_PROTO.get_root=function() {
    return this.data_store;
}
CURRENT_PROTO.get=function(key) {
    var tokens = key.split(/\./) || [];
    var root = this.data_store;
    var v = null;
    for(var i=0; i < tokens.length ; i++) {
        root = this._eval_one_token(tokens[i], root, true);
        v = root;
        if(Ext.isEmpty(root))
            break;
    }
    return (Ext.isEmpty(v) ? null : v);
    //return eval(this._compute_eval(key));
}
CURRENT_PROTO.set=function(key,value) {
    var tokens = key.split(/\./) || [];
    var last_token = null;
    var root = this.data_store;
    for(var i=0; i < tokens.length ; i++) {
        if(i == tokens.length - 1) {
            last_token = tokens[i];
            break;
        }
        root = this._eval_one_token(tokens[i], root);
    }
    this._set_token_value(root, last_token, value);

//    var root = null;
//    Ext.each(tokens, function(t) {
//        root = this._eval_one_token(t, root);

//    }, this);

//    var k = this._compute_eval(key);
//    var re_array = /\[(\w+)\]$/;
//    var re_dot = /\.(\w+)$/;
//    if(k.match(re_array)) {
//        var idx = RegExp.$1;
//        k = k.replace(re_array,'');
//        var root = eval(k);
//        if(root) {
//            if(Ext.isArray(root))
//                root[Number(idx)] = value;
//            else
//                root[idx] = value;
//        }
//    } else if(k.match(re_dot)) {
//        var idx = RegExp.$1;
//        k = k.replace(re_dot,'');
//        var root = eval(k);
//        root[idx] = value;
//    } else {
//        eval(k) = value;
//    }

    if(!this._initializing) this.fireEvent('datachanged', key, value, this);
    return value;
}
CURRENT_PROTO._set_token_value=function(root, key, value) {
    var idx = null;
    if(key.match(this.idx_re)) {
        idx = RegExp.$1;
        key = key.replace(this.idx_re, '');
    }
    var ret = root;
    var is_idx_null = Ext.isEmpty(idx);
    if(key.length > 0 && !is_idx_null) {
        if(!(key in root))
            root[key] = Ext.num(idx,null) == null ? {} : [];
        root[key][Ext.num(idx,idx)] = value;
    } else if(key.length == 0 && !is_idx_null) {
        root[idx] = value;
    } else if(key.length > 0 && is_idx_null) {
        root[key] = value;
    } else if(key.length == 0 && is_idx_null) {
        throw new Error('Both key and idx cannot be null . Passed key : ' + key);
    }
}
CURRENT_PROTO._eval_one_token=function(token, root, no_vivi) {
    root = root || this.data_store;
    var idx = null;
    if(token.match(this.idx_re)) {
        idx = RegExp.$1;
        token = token.replace(this.idx_re, '');
    }
    var ret = null;
    if(token.length > 0) {
        if(token in root)
            ret = root[token];
        else if(!no_vivi){
            var v = Ext.num(idx, null);
            if(v == null) {
                ret = root[token] = {};
            }
            else
                ret = root[token] = [];
        }
    } else {
        ret = root;
    }
    if(!Ext.isEmpty(idx) && !Ext.isEmpty(ret)) {
        ret = ret[Ext.num(idx,idx)];
    }
    return ret;
}
CURRENT_PROTO.clear=function() {
    this.data_store = {};
    if(!this._initializing) this.fireEvent('cleared',this);
}
CURRENT_PROTO.remove=function(key) {
    var tokens = key.split(/\./) || [];
    var last_token = null;
    var root = this.data_store;
    var v = null;
    for(var i=0; i < tokens.length ; i++) {
        if(i == tokens.length - 1) {
            last_token = tokens[i];
            break;
        }
        root = this._eval_one_token(tokens[i], root, true);
        if(root == null)
            break;
    }
    if(root != null) {
        key = last_token;
        var idx = null;
        if(last_token.match(this.idx_re)) {
            idx = RegExp.$1;
            key = last_token.replace(this.idx_re, '');
        }
        var ret = root;
        var is_idx_null = Ext.isEmpty(idx);
        if(key.length > 0 && !is_idx_null) {
            root = root[key];
            if(root != null) {
                if(Ext.isArray(root))
                    v= root.splice(Number(idx), 1);
                else {
                    v = root[idx];
                    delete root[idx];
                }

            }
        } else if(key.length == 0 && !is_idx_null) {
            if(Ext.isArray(root))
                v = root.splice(Number(idx), 1);
            else {
                v = root[idx];
                delete root[idx];
            }
        } else if(key.length > 0 && is_idx_null) {
            v = root[key];
            delete root[key];
        } else if(key.length == 0 && is_idx_null) {
            throw new Error('Both key and idx cannot be null for delete. Passed key : ' + key); }
    }

//    var k = this._compute_eval(key);
//    var re = /\[(\w+)\]$/;
//    var v = this.get(key);
//    if(k.match(re)) {
//        var idx = RegExp.$1;
//        k = k.replace(re,'');
//        var root = eval(k);
//        if(root) {
//            Ext.isArray(root) ? root.splice(Number(idx),1) : (delete root[idx]);
//        }
//    } else {
//        eval('delete '+k);
//    }
    if(!this._initializing) this.fireEvent('removed',key,v,this);
    return v;
}

/**
   To be called once after the page loads and all components have been laid out. This will fire a change event ONCE for each top level key
*/
CURRENT_PROTO.init=function() {
    this._initializing=true;
    for(var k in this.data_store) {
        var v = this.data_store[k];
        this.fireEvent('datachanged', k, v, this);
    }
    this._initializing=false;
}
