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
}