
/*=============================================================================================
	author:ZhaoJun
	version:1.2
	email:2454713902@qq.com
=============================================================================================*/


//严格模式
/*-------------------------------------------------------------------------------------------*/	
'use strict';
/*-------------------------------------------------------------------------------------------*/	
    

//生成表
/*-------------------------------------------------------------------------------------------*/	    
class generate
{  

    static async index(table,eng)
    {
        let sql=''
        switch (eng) 
        {
            case 'postgresql':
                sql=
                `
                    SELECT A.SCHEMANAME, A.TABLENAME, A.INDEXNAME,A.TABLESPACE,A.INDEXDEF,B.AMNAME,
                    C.INDEXRELID,C.INDNATTS,C.INDISUNIQUE,C.INDISPRIMARY,C.INDISCLUSTERED,D.DESCRIPTION
                    FROM PG_AM B
                    LEFT JOIN PG_CLASS F ON B.OID = F.RELAM
                    LEFT JOIN PG_STAT_ALL_INDEXES E ON F.OID = E.INDEXRELID
                    LEFT JOIN PG_INDEX C ON E.INDEXRELID = C.INDEXRELID
                    LEFT OUTER JOIN PG_DESCRIPTION D ON C.INDEXRELID = D.OBJOID,
                    PG_INDEXES A
                    WHERE
                    A.SCHEMANAME = E.SCHEMANAME AND A.TABLENAME = E.RELNAME AND A.INDEXNAME = E.INDEXRELNAME
                    AND E.RELNAME = '${table}'
                `
            break;
            case 'mysql':
                let reg=/  (\w*?\s.*?)[,|\n]/ig
                let arrObj=[]
                let result
                while (result=reg.exec(table)) 
                {
                    arrObj.push(result[1])
                }
                return arrObj
            break;
        }
        let indexs=await generate.query.comQer(sql)
        if(eng=='postgresql')indexs=indexs.rows
        let arr=[]
        for (let index = 0; index < indexs.length; index++) 
        {
            let cur=indexs[index]
            arr.push(cur.indexdef)
        }
        return arr
    }

    static async field(table,eng)
    {
        let sql
        switch (eng) 
        {
            case 'postgresql':
                sql=
                `
                SELECT a.attnum,a.attname AS field,t.typname AS type,
                a.attlen AS length,a.atttypmod AS lengthvar,a.attnotnull AS notnull,
                b.description AS comment
                FROM pg_class c,pg_attribute a
                LEFT OUTER JOIN pg_description b ON a.attrelid=b.objoid AND a.attnum = b.objsubid,
                pg_type t
                WHERE c.relname = '${table}'
                and a.attnum > 0
                and a.attrelid = c.oid
                and a.atttypid = t.oid
                ORDER BY a.attnum
                `
            break;
            case 'mysql':
                let reg=/  `(.*?)\n/ig
                let arrObj={}
                let result
                while (result=reg.exec(table)) 
                {
                    let obj={}
                    let str=result[0]


                    let regField=/`(.*?)`/g
                    let cur,field

                    let regComment=/COMMENT '(.*?)'/g
                    if(cur=regComment.exec(str))obj.comment=cur[1]
                    else obj.comment=''

                    if(cur=regField.exec(str))field=cur[1]
                    let regType=/\s(\S*?)\((.*?)\)/g
                    if(cur=regType.exec(str))
                    {
                        obj.type=cur[1]
                        obj.length=cur[2]
                    }
                    else 
                    {
                        regType=/`\s(\S*?)\s/g
                        cur=regType.exec(str)
                        obj.type=cur[1]
                    }

                    if(str.indexOf('NOT NULL')!=-1)obj.notnull='NOT NULL'
                    else obj.notnull=''

                    if(str.indexOf('AUTO_INCREMENT')!=-1)obj.auto=true

                    let regDef=/\sDEFAULT '(.*?)'/g
                    if(cur=regDef.exec(str)) obj.default=cur[1]

                    arrObj[field]=obj
                }
                return arrObj
            break;
        }

        let fields=await generate.query.comQer(sql)
        if(eng=='postgresql')fields=fields.rows
        
        let obj={}
        for (let index = 0; index < fields.length; index++) 
        {
            let cur=fields[index]
            obj[cur.field]={comment:cur.comment,type:cur.type+`(${cur.length})`,meta:cur.notnull?'not null':''}
        }
        return obj
    }

    static meta(table,eng)
    {
        let result
        switch (eng) 
        {
            case 'postgresql':
                result= ''
            break;
            case 'mysql':
                result=table.replace(/.*?COMMENT='(.*?)'/is,'$1')
            break;
        }
        return result
    }

    static eng(table,eng)
    {
        let result
        switch (eng) 
        {
            case 'postgresql':
                result= ''
            break;
            case 'mysql':
                let reg= /.*?ENGINE=(.*?)\s.*/is
                if(reg.test(table))
                {
                    result=table.replace(reg,'$1')
                }
                else result=''
            break;
        }
        return result
    }

    static meta(table,eng)
    {
        let result
        switch (eng) 
        {
            case 'postgresql':
                result= ''
            break;
            case 'mysql':
                let reg=/.*?DEFAULT CHARSET=(.*?)[\s|$].*/is
                if(reg.test(table))result=table.replace(reg,'$1')
                else result=''
            break;
        }
        return result
    }

    static async mysql(table)
    {
        let result=await generate.query.comQer('show create table '+table)
        if(result)result=result[0]['Create Table']
        else result=''
        return result 
    }

    static async tables(eng='postgresql',type='main')
    {
        generate.query=$Sys.orm.eng(eng).db(type)
        let sql=await $Sys.model('/db/build','isRegTable',[eng,true])
        let tables=await generate.query.comQer(sql)
        if(eng=='postgresql')tables=tables.rows

        for (let index = 0; index < tables.length; index++) 
        {
            let result=(eng=='postgresql')?tables[index].tablename:await generate.mysql(tables[index].tablename)
            tables[index].field=await generate.field(result,eng)
            tables[index].index=await generate.index(result,eng)
            tables[index].eng=await generate.eng(result,eng)
            tables[index].meta=generate.meta(result,eng)
            tables[index].type=eng
            tables[index].as=type
            tables[index].db=$Db[eng+'Opt'].main.database
        }

        return tables
    }

    static async init(typeEng='mysql')
    {
        async function back(eng='postgresql',type='main')
        {
            let tables=await generate.tables(eng,type)
            let str = ''
            let db
            let int=0
            for (let index = 0; index < tables.length; index++) 
            {
                let cur=tables[index]
                db=cur.db
                let ext={$comment:cur.comment,$index:cur.index,$type:cur.type,$as:cur.as,$meta:cur.meta,$eng:cur.eng}
                str+=generate.format(cur.tablename,cur.field,ext)
                
                if(index!=0 && index%5===0)
                {
                    if(int===0)generate.outInner(str,db,eng+'')
                    else generate.outInner(str,db,eng+'_'+int)
                    int++
                    str=''
                }
            }

            if(int===0)generate.outInner(str,db,eng+'')
            else generate.outInner(str,db,eng+'_'+int)
        }
        await back(typeEng)

        return true
    }

    static format(tablename,json,extend)
    {
    
        if(typeof json != 'object')return '{}'
        let str='\tstatic '+tablename+'()\r\n\t{\r\n\t\tlet table=\r\n'+'\t\t{\r\n'
        function field(key,count=3)
        {
            let str=''
            let tab='\t'.repeat(count)
            let tab4='\t'.repeat(count+1)
            str+=tab+key+':\r\n'+tab+'{\r\n'+tab4+'private:{'
            for (const keyp in json[key]) 
            {
                if(keyp=='comment')continue
                str+=keyp+':'+'"'+json[key][keyp]+'"'+','
            }

            str=str.replace(/,$/g,'')
            str+='},\r\n'+tab4+'extends:{descript:"'+(json[key].comment?json[key].comment:'')+'",escape:true}'
            return [str,tab]
        }
    
    
        for (const key in json) 
        {
            let [_str,_tab]=field(key)
            str=str+_str+'\r\n'+_tab+'},\r\n'
        }
        str=str.replace(/\n$/g,'')
        str+='\t\t}\r\n\r\n'
    
        for (const key in extend) 
        {
            if(Array.isArray(extend[key]))
            {
                str+='\t\ttable.'+key+'='+JSON.stringify(extend[key])+'\r\n'
            }
            else
            {
                str+='\t\ttable.'+key+'="'+extend[key]+'"\r\n'
            }
        }
        str=str.replace(/\n$/g,'\t\treturn table;\n')
        str+='\t}\r\n\r\n'
        return str
    }
    
    static outInner(str,db='vsmart',version='')
    {
        let fs=require('fs')
        let _str=
        `/*=============================================================================================
            author:ZhaoJun
            version:1.2
            email:2732810281@qq.com
        =============================================================================================*/


        //严格模式
        /*-------------------------------------------------------------------------------------------*/	
        'use strict';
        /*-------------------------------------------------------------------------------------------*/	
            
    
        //生成表
        /*-------------------------------------------------------------------------------------------*/	\r\n`
        .replace(/\ {4}/g,'')
    
        str=_str+'class '+db+'_db\r\n{\r\n'+str
        str+='\r\n}\r\n/*-------------------------------------------------------------------------------------------*/'
        str+='\r\n\r\nmodule.exports='+db+'_db; '
        fs.writeFileSync($Config.root+'/nodejs/mould/'+db+'_'+version+'_vsmartPrivate.js',str)
        return str
    }

}
/*-------------------------------------------------------------------------------------------*/	 
module.exports=generate;