$Route={};
$Route.filter=new Map()//用于过滤路由
$Route.requireTag=true//用于标识是否继续执行绘制函数,用于误渲染。但可能造成问题，先关闭
$Route.requireTagIgnore=true//忽略，继续执行绘制函数的标识
$Route.$stop=false//是否启用$select
$Route.$select={}//让正在正在进行中的路由，不渲染界面
$Route.$map={}
$Route.$tag=true//用hash，还是search
$Route.$state={path:'',unique:''}

$Route.notFind=''//未找到路径时，跳转到此路径


$Route.set404=function(str)
{
    if(typeof str === 'string')
    {
        $Route.notFind=str
    }
}

$Route.current=function()
{
    if($Route.$tag)
    {
        let cur=$M.param().$route
        cur=cur?cur:''
        return cur;
    }
    else
    {
        return location.hash.slice(1);
    }
}
$Route.load=function(data)
{
    let root=data.$root
    if(data.$content===undefined)data.$content={}
    data.$contentTag=[];
    if(root)
    {
        function back(data)
        {
            for (const key in data) 
            {
                if(data[key] instanceof Object)
                {
                    if(key=='$path')
                    {
                        for (const k in data[key]) 
                        {
                            if(data[key][k].url)data[key][k].url=root+data[key][k].url;
                        }
                    }
                    else
                    {
                        back(data[key])      
                    } 
                }
            }
        }
        back(data)
    }
    else
    {
        data.$root=''
    }
    if(!data)return false
    $Route.$map=data
    return true
}
$Route.param=function(no=[],param)
{
    let obj=$M.param(param)
    let back={need:{},other:{}}
    if($Route.$tag)
    {
        for (const key in obj) 
        {
            if(key=='$route')
            {
                back.need[key]=obj[key]
                continue
            }
            if(!no.includes(key))
            {
                back.other[key]=obj[key]
            }
            else
            {
                back.need[key]=obj[key]
            }
        }
    }
    else
    {
        back.need.$route=location.hash
        back.other=obj
    }
    return back
}

//把自定义选择器，解析成标准选择器
$Route.getQuery=function(id)
{
    //如果发现#前缀，则保持原样，不进行操作。
    //一般用在子页面的，局部组件。
    //加了#前缀，会自动编译#为_hash_形式
    //这个判断条件一定不要删除，就算以后不理解也不要删
    //这是写给自己备忘的
    if(id.indexOf('#')!=0)
    {
        //只有@前缀
        //自定义选择器，不一定用id选择
        if(id.indexOf('@')==0)
        {
            id=id.slice(1);
        }
        else if(id.indexOf('!')==0)
        {
            //#全局id，前缀为!
            id='#'+id.slice(1);
        }
    }
    return id;
}

//引用组件
$Route.require=async function(obj)
{
    let timeNow=Date.now()
    $Route.requireTag=false
    try 
    {
        for (let index = 0; index < obj.length; index++) 
        {
            let result=[]
            if(!obj[index])continue
            if($Route.requireTag && !$Route.requireTagIgnore)return
            for (let ind = 0; ind < obj[index].length; ind++) 
            {
                let cur=obj[index][ind]
                cur.select=$Route.getQuery(cur.select);

                $Route.$select[cur.select]=timeNow

                //是否有缓存的页面内容
                let resultString=$Route.$map.$content[cur.url]
                if(resultString)
                {
                    if($Route.$map.$contentTag.includes(cur.url))
                    {
                        cur.$content=resultString
                    }
                    else
                    {
                        let result=unescape(resultString)
                        cur.$content=result
                        $Route.$map.$contentTag.push(cur.url)
                        $Route.$map.$content[cur.url]=result
                    }
                }

                cur.$callParam=obj.$callParam
                cur.now=timeNow
                result.push($Draw.getPage(cur))
            }
            await Promise.all(result)
                        
        }   
    } 
    catch (error) 
    {
        $M.info('【route】引用组件错误',error)
        return
    }
    $Route.requireTag=true
}

//用户点击频率
$Route.getTime=function(dom)
{
    var curtime=dom.getAttribute('route-time');
    return curtime?curtime:500;
}

//用于执行脚本上的函数
$Route.exec=async function(dom)
{
    if(!(dom && dom.tagName))
    {
        return false;
    }
    if(dom._click)
    {
        return false;
    }
    dom._click=true;
    
    setTimeout
    (
        function()
        {
            dom._click=false;
        }, $Route.getTime(dom)
    )
    var route_exec=dom.getAttribute('route-exec')
    if(!route_exec)
    {
        $M.info('【route】没有可执行的函数操作')
        return false;
    }

    try 
    {
        await $M.eval(route_exec,dom);
        return false;
    } 
    catch (error) 
    {
        $M.info('【route】路由函数操作失败：'+route_exec);
        return false;
    }
}

$Route.filterFun=function(path,data='')
{
    for (const iterator of $Route.filter) 
    {
        if(typeof iterator[0] == 'string')
        {
            if(path.indexOf(iterator[0])!=-1)
            {
                let result=iterator[1](path,data);
                if(result!==undefined)return result;
            }
        }
        else if(iterator[0] instanceof RegExp)
        {
            if(iterator[0].test(path))
            {
                let result=iterator[1](path,data);
                if(result!==undefined)return result;
            }
        }
    }
}

$Route.match=function(str='',param)
{
    if($Route.$tag)
    {
        if(param)str='?'+param+'&$route='+str
        else str='?$route='+str
    }
    else 
    {
        if(param)str='?'+param+'#'+str
        else str='#'+str
    }
    return str;
}

//向浏览器，推送路径
$Route.push=function(dom,paramR,rep,globalTag)
{
    var str,param
    if(!dom)
    {
        $M.info('【route】不是一个可用对象');
        return false;
    }
    if(dom.tagName)
    {
        if(dom._click)
        {
            return false;
        }
        dom._click=true;
        
        setTimeout
        (
            function()
            {
                dom._click=false;
            },$Route.getTime(dom)
        )
        str=dom.getAttribute('route-url')
        param=dom.getAttribute('route-param')
        rep=dom.getAttribute('route-replace')
    }
    else if(typeof dom == 'string')
    {
        str=dom
        if(paramR instanceof Object)
        {
            param=$M.unParam(paramR)
        }
    }
    else if(dom instanceof Object)
    {
        str=dom.url
        param=$M.unParam(dom.param)
        rep=dom.replace  
    }
    let path=str;

    if(!str)
    {
        $M.info('【route】没有路由路径')
        return false;
    }

    
    str=$Route.match(path,param)

    if($Route.$state.unique==str)
    {
        $M.info('【route】路由没有变化，不更新',str)
        return;
    }
    $Route.$state.unique=str

    let result=$Route.filterFun(path,param)
    if(result!==undefined)return

    if(rep)
    {
        history.replaceState({time:new Date(),url:location.hash},'',str)
    }
    else
    {
        history.pushState({time:new Date(),url:location.hash},'',str)
    }
    $Route.link(true,globalTag)
    return true;
}

$Route.replace=function(dom)
{
    $Route.push(dom,true)
}

$Route.gen=function(url)
{
    if(!url)return [];
    if(url[0]==='#')url=url.slice(1)
    return url.split(/@/g)
}

//把浏览器，的地址解析成可用的路由对象
$Route.link=async function(tagFilter,globalTag)
{
    let $r=$Route.param()
    let $rn=$r.need.$route
    var url=$Route.gen($rn)
    var urlBefore=$Route.gen($Route.$state.path)

    if(!tagFilter)
    {
        let resultBack=$Route.filterFun($rn,$r.other)
        if(resultBack!==undefined)return
    }
    
    var store=$Route.$map
    let result=[]
    let tag
    
    for (const key in url) 
    {
        store=store[url[key]]
        //带有$rely标识，则从本级开始更新组件
        if(tag || url[key]!=urlBefore[key] || (store && store.$rely) || (!$Route.requireTag && !$Route.requireTagIgnore))
        {
            tag=true
            if(store)
            {
                let swap=store
                if(Array.isArray(swap.$path))
                {
                    result.push(swap.$path)   
                }
            }
            else
            {
                $M.info('【route】不是一个路径',url[key]);
                if($Route.notFind && !globalTag)$Route.push($Route.notFind,undefined,undefined,true)
                return false;
            }   
        }
    }

    if(result.length===0)result=[store.$path]
    $Route.require(result);
    $Route.$state={path:$rn,unique:$Route.match($rn,$M.unParam($r.other))}
}

//组件调用，不会往历史记录推
$Route.call=async function(path,callParam,id)
{
    if(callParam===undefined)callParam={};
    let url=$Route.gen(path);
    var store=$Route.$map
    let result=[]
    
    for (const key in url) 
    {
        store=store[url[key]]
        if(store)
        {
            let swap=store
            if(Array.isArray(swap.$path))
            {
                if(id)
                {
                    for (const key in swap.$path) 
                    {
                        swap.$path[key].select=id
                    }
                }
                result.push(swap.$path)   
            }
        }
        else
        {
            $M.info('【route-call】不是一个路径,不会重定向',url[key]);
            return false;
        } 
    }

    let resultBack=$Route.filterFun(path,$M.unParam(callParam))
    if(resultBack!==undefined)return

    if(callParam instanceof Object)callParam=JSON.stringify(callParam);
    result.$callParam=callParam

    await $Route.require(result);
}



//开始监听前进后退
$Route.init=function(dom)
{
    if($Route.$tag)
    {
        let $r=$M.param().$route
        if(!$r)$Route.push(dom,undefined,true)
        else $Route.link()
    }
    else
    {
        if(!location.hash)$Route.push(dom,undefined,true)
        else $Route.link()
    }

    window.onpopstate=function(event)
    {
        $Route.link();
    }
}
