# src/model.js File

    import { createReducer } from 'gfs-react-redux-twoway-binding'
    import Immutable from 'immutable'
    /**
     * 实体、数据模型，model中的方法和属性都该设置成静态类型
     * @class Model
     * */
    //需要一个队列保存model
    let __gfs_mvc_m_list = {}
    let __gfs_mvc_m_actiontypes = {}

    export const DEFAULT_METHOD_FIX = '$$'
    export const DEFAULT='default'

    function getField(data,path){
        try{
            var newpath = path.concat()
            for(var i=0,len=newpath.length,p,v;i<len;i++){
                //如果path不是最后一个
                if(i!=len){
                    p = newpath.slice(0,i+1)
                    v = data.getIn(p)
                    if(!v ){
                        data = typeof(v)=='undefined' ? data.mergeIn(p.slice(0,p.length-1),Immutable.fromJS({
                            [p[p.length-1]]:{}
                        }) ) : data.setIn(p,{})
                    }
                }
            }

        }catch(ex){
            console && console.warn && (console.warn(ex) )
        }

        return data
    }

    function merger(prev,next){
        if( Immutable.List.isList(prev) &&  Immutable.List.isList(next)){
            return next
        }
        if(prev && prev.mergeWith){
            return prev.mergeWith(merger,next)
        }
        return next
    }

    let curl = {
        del:function(data,action){
            return data.deleteIn(action.path)
        },
        update:function(data,action){
            data = getField(data,action.path)
            if(typeof(action.data) ==='string' && action.path){
                return data.setIn(action.path,action.data)
            }
            action.data = Immutable.fromJS(action.data)
            return action.path ? data.mergeDeepIn(action.path,action.data ) : data.mergeDeep(action.data )
        },
        updateWith:function(data,action){
            //data = getField(data,action.path)
            if(typeof(action.data) ==='string' && action.path){
                return data.setIn(action.path,action.data)
            }
            action.data = Immutable.fromJS(action.data)
            return data.mergeWith(action.merge ? action.merge:merger,action.data )
        },
        save:function(data,action){
            data = getField(data,action.path)
            return data.setIn(action.path,action.isImmutable ?Immutable.fromJS(action.data) : action.data)
        },
        insert:function(data,action){
            data = getField(data,action.path)
            return data.setIn(action.path,action.isImmutable ?Immutable.fromJS(action.data) : action.data)
        },
        query:function(data){
            return data
        },
        findOne:function(data,action){
            return data.getIn(action.path)
        },
        find:function(data,action){
            return data.getIn(action.path)
        }
    }

    function implement(target={},modelName='',param={property:{},method:{}},fix=''){
        let property = param.property
        let method = param.method

        if(fix){
            fix+=DEFAULT_METHOD_FIX
        }
        for(let item in target){
            if(!(target[item] instanceof Function) ){
                property[item] = target[item]
            }else{
                method[`${fix}${modelName}${DEFAULT_METHOD_FIX}${item}`] = target[item].bind(target)
                //__gfs_mvc_m_actiontypes[`${fix}${modelName}${DEFAULT_METHOD_FIX}${item}`] = `${fix}${modelName}${DEFAULT_METHOD_FIX}}${item}`
            }

        }

        return {
            property:property,
            method:method
        }
    }

    /**
     * 一个类装饰器，被装饰的类会变成store，默认不需要额外提供对数据操作的方法，在control中默认会提供del、update、insert等数据操作方法；如果有特殊需求无法满足使用场景可按照example中给出的方式自行编写数据处理方法<br />
     * <strong style="color:red">注意：model类中`__name`属性必须要有，这是为了能在各个component正常使用model必备的一个属性,必须小写，默认会在字符串后面添加上"model",例如：`static __name='test'`,那么在实际中运用应该是this.props.testmodel</strong>
     * @method Model
     * @param target {object} 被包装的对象
     * @example
     *
     *       import {Model} from 'gfs-react-mvc'
     *       //这里由于@为文档关键符号，所以下面将以$代替
     *       //@Model
     *       $Model
             class TestModel {
                //__name必须要有，这是为了能再各个component正常使用model必备的一个属性,必须小写
                static __name = 'testmodel'
                //数据模型
                static age = 20
                static xq = {}
                //可以自行定义数据操作方法，在control中通过
                //dispatch({
                //    type:`testmodel$$save`,
                //    data:data
                //})
                //这种方式变更数据，其中type值的组成是通过：类名（全小写）+ 方法名组成
                static save(data, action){
                    if(action.data){
                        return data.merge(Immutable.fromJS(action.data) )
                    }
                }
                //dispatch({
                //    type:`testmodel$$del`,
                //    data:data
                //})
                static del(data, action){
                    if(action.data){
                        return data.merge(Immutable.fromJS(action.data) )
                    }
                }
            }
     * */
    export  function Model(target){
        let params={}
        //读取字段组成新的对象
        if(typeof(target.__name) == 'undefined' ){
            console && console.warn('[create model error] ','Model中必须存在__name属性，并赋予store名称，例如: static __name="testmodel"')
            return {
                modelName:'',
                store:null
            }
        }
        let modelName = target.__name.toLowerCase()

        if(modelName.indexOf('model')<=-1){
            modelName+='model'
        }
        //取得属性或方法
        params = implement(target,modelName)
        params = implement(curl,modelName,params,DEFAULT)
        // params = implement(target.prototype,modelName,params)

        let store = createReducer(modelName, Immutable.fromJS(params.property||{} ), params.method)

        __gfs_mvc_m_list[`${modelName}`]=store

        return {
            modelName:modelName,
            store:store
        }

    }

    export function getActionTypes(typeName){
        return __gfs_mvc_m_actiontypes[typeName]
    }

    export function getModels(){
        return __gfs_mvc_m_list
    }

    export function emptyModels(){
        __gfs_mvc_m_list = null
        //delete __gfs_mvc_m_list
    }