#!/usr/bin/env node

const {lstatSync, readdirSync} = require('fs')
const fs = require('fs')
const {join, resolve,dirname,basename} = require('path')
const {getFormSpecs, flattenFormSpecs} = require('./dsl')
const {genTableSql} = require('./table_mysql.js');
const template = require('art-template')
const path = require('path');

const isDirectory = source => lstatSync(source).isDirectory()
const isFile = source => {
    try {
        return fs.statSync(source).isFile()
    } catch (e) {
        return false
    }
}

var model_git_version = 'unknown';
try{
    model_git_version =  require('child_process')
        .execSync('git rev-parse HEAD')
        .toString().trim();
}
catch(e){
    console.log('error while get git version');
    // console.log(e);
}

const owl_version = require('../package.json').version;

function getProjectCode(owl) {
    if (owl._t && owl.prefix) {
        return owl.prefix + owl._t.toLowerCase();
    } else {
        return "owl_"+owl._t.toLowerCase();
    }
}


function getProjectName(owl) {
    if (owl['#meta']) {
        return owl['#meta'].projectName
    }
    return null
}

function getMeta(owl) {
    return owl['#meta']
}

let cwd = process.cwd();
console.log("cwd=",cwd)

var desktopDistDir = ''
var libpath = 'undefined'
var buildProperties = 'undefined'


function mkdir(path) {
    try {
        fs.mkdirSync(path)
    } catch (e) {
    }
}

function getIndexMapping(flatternedSpecs){
    var allFields = flatternedSpecs.allFields;
    var propMappings = {};
    var stockFields = ["owl_createTime","m","_t","_v","_orgIds","_orgId","del","owl_createUserId","owl_lastModifiedUserId","owl_modifyTime","owl_createTime"];
    for(var i=0; i<allFields.length; i++){
        var field = allFields[i];

        if(stockFields.indexOf(field.key)>=0){
            continue;
        }
        if(field.fieldType == 'date'){
            propMappings[field.key] = {
                "type":"date"
            };

        }
        else if(field.fieldType == 'string' || field.fieldType == 'choice' || field.fieldType == 'linkId'){
            propMappings[field.key] = {
                "type":"text",
                "fields": {
                    "keyword": {
                        "type": "keyword",
                        "ignore_above": 256
                    }
                }
            };
        }
        else if(field.fieldType=='number'){
            propMappings[field.key] = {
                "type":"double"
            };
        }
    }
    if(Object.keys(propMappings).length>0){
        var s = JSON.stringify(propMappings);
        s = s.substring(1);
        s = s.substring(0,s.length-1);
        return "," + s;
    }
    return "";
}
function processOwl(owl, outdir, templatePath, buildType, inputFile) {
    var projectCode = getProjectCode(owl)
    var projectName = getProjectName(owl)
    var meta = getMeta(owl)
    var formSpecs = getFormSpecs(owl, '')
    var flattenedSpecs = flattenFormSpecs(formSpecs)
    var id = meta.id
    var idFunc = 'null'
    var lockFunc = 'null'
    var lock = meta.lock
    if (id) {
        idFunc = template.compile(id).toString()
    }

    if (lock) {
        lockFunc = template.compile(lock).toString()
    }

    if (!projectCode) {
        console.log(inputFile + ' is not a valid owl file,no projectCode')
        return
    }
    if (!projectName) {
        console.log(inputFile + ' is not a valid owl file,no projectName')
        return
    }

    //  处理templatePath里面的每一个文件
    var fullTemplatePath = templatePath;
    readdirSync(fullTemplatePath).map(name => {
        if (name === 'node_modules') {
            return
        }

        // if (buildType !== 'debug' && name === 'desktop' && outdir.indexOf('erp_owl') === -1) {
        //    return
        // }

        var fullname = resolve(fullTemplatePath, name)
        if (isDirectory(fullname)) {
            var subOutDir = resolve(outdir, name)
            mkdir(subOutDir)
            processOwl(owl, subOutDir, fullname, buildType, inputFile)
            return
        }
        var dst = resolve(outdir, name)
        if (name.indexOf('.png') > -1 || name.indexOf('.PNG') > -1 ||
            name.indexOf('.jpg') > -1 || name.indexOf('.jpeg') > -1 ||
            name.indexOf('.JPG') > -1 || name.indexOf('.JPEG') > -1) {
            fs.copyFileSync(fullname, dst)
            return
        }

        let tableInfos = genTableSql(projectCode,formSpecs);
        let tablesql = tableInfos[0].join("\n\n");
        let tables = JSON.stringify(tableInfos[1]);

        var fileContent = fs.readFileSync(fullname, {encoding: 'utf-8'})

        var dynamicIndex  = owl["_dynamicIndex"];
        if(!dynamicIndex){
            dynamicIndex = "false";
        }
        fileContent = fileContent.replace(/@projectCode/g, projectCode)
        fileContent = fileContent.replace(/@dynamicIndex/g, dynamicIndex)


        fileContent = fileContent.replace(/@projectName/g, projectName)
        fileContent = fileContent.replace(/@meta/g, JSON.stringify(meta))
        fileContent = fileContent.replace(/@formSpecs/g, JSON.stringify(formSpecs))
        fileContent = fileContent.replace(/@flattenedSpecs/g, JSON.stringify(flattenedSpecs))
        fileContent = fileContent.replace(/@fieldMappings/g, getIndexMapping(flattenedSpecs));
        fileContent = fileContent.replace(/@desktopDistDir/g, desktopDistDir)
        fileContent = fileContent.replace(/@idFunc/g, idFunc)
        fileContent = fileContent.replace(/@idOrig/g, id)
        fileContent = fileContent.replace(/@lockFunc/g, lockFunc)
        fileContent = fileContent.replace(/@lockOrig/g, lock)
        fileContent = fileContent.replace(/@buildProperties/g, buildProperties)
        fileContent = fileContent.replace(/@libpath/g, libpath)
        fileContent = fileContent.replace(/@model_git_version/g, model_git_version)
        fileContent = fileContent.replace(/@owl_version/g, owl_version)
        fileContent = fileContent.replace(/@tablesql/g, tablesql)
        fileContent = fileContent.replace(/@tables/g, tables)

        var eventHandlers = owl['#meta']['eventHandlers'];
        if(!eventHandlers){
            eventHandlers = [];
        }
        fileContent = fileContent.replace(/@eventHandlers/g, JSON.stringify(eventHandlers))


        var jobs = owl['#meta']['jobs'];
        if(!jobs){
            jobs = [];
        }
        fileContent = fileContent.replace(/@jobs/g, JSON.stringify(jobs))


        //去掉owl里面的敏感信息
        var spec = JSON.parse(JSON.stringify(owl));
        delete spec['#meta']['eventHandlers'];
        delete spec['#meta']['jobs'];
        fileContent = fileContent.replace(/@spec/g, JSON.stringify(spec))

        dst = resolve(outdir, name)
        fs.writeFileSync(dst, fileContent, {flag: 'w'})
    })
}


function setProject(owl, project){
    owl["#meta"]["project"] =  project;
}

//处理一个文件的主入口
function processOwlFile(dir,name, outdir, templatePath, buildType, modelDir,project) {
    var inputFile = resolve(dir,name);
    console.log('going to process file:',inputFile);
    var content = fs.readFileSync(inputFile, {encoding: 'utf-8'})
    var owl = JSON.parse(content)
    var projectCode = getProjectCode(owl)
    var projectName = getProjectName(owl)
    if (!projectCode) {
        console.log(inputFile + ' is not a valid owl file,no projectCode')
        return
    }
    if (!projectName) {
        console.log(inputFile + ' is not a valid owl file,no projectName')
        return
    }
    setProject(owl,project);

    var owlProjectDir = join(outdir, projectCode)
    try {
        fs.mkdirSync(owlProjectDir)
    } catch (e) {
    }

    var formSpecs = getFormSpecs(owl, '')
    formSpecs["tableName"] = projectCode;
    formSpecs["_t"] = owl._t;

    var flattenedSpecs = flattenFormSpecs(formSpecs)
    //写入转换过的formspec.json
    var formspecDir = resolve(outdir,"_formspecs");
    // console.log("write formspects to " + formspecDir);
    mkdir(formspecDir);

    var formspecFile = resolve(formspecDir,"formspec_" + name);
    // console.log("writing file:" + formspecFile);
    fs.writeFileSync(formspecFile,JSON.stringify(formSpecs),{flag:'w'});

    processOwl(owl, owlProjectDir, templatePath, buildType)
    var owlProjectApiSrcDir = join(owlProjectDir, 'api/src')

    var extraTemplatePath = join(dir, owl._t)
    console.log("owlProjectDir="+owlProjectDir + ":extraTemplatePath=" + extraTemplatePath);
    if (fs.existsSync(extraTemplatePath) && isDirectory(extraTemplatePath)) {
        processOwl(owl, owlProjectDir, extraTemplatePath, buildType)
    }
    // 复制导出文件
    if (fs.existsSync(owlProjectApiSrcDir) && isDirectory(owlProjectApiSrcDir)) {
        var excelTemplate = join(modelDir, projectCode + '.xlsx')
        if (isFile(excelTemplate)) {
            var dst = join(owlProjectApiSrcDir, projectCode + '.xlsx')
            fs.copyFileSync(excelTemplate, dst)
        }
    }
}

function processInputDir(dir, outdir, templatePath, buildType, project) {
    readdirSync(resolve(cwd, dir)).map(name => {
        if(name == 'api' || name=='sql'){
            return;
        }
        if (isDirectory(resolve(dir, name))) {
            try {
                fs.mkdirSync(resolve(outdir, name))
            } catch (e) {
            }
            processInputDir(resolve(dir, name), resolve(outdir, name), templatePath, buildType,project)
        } else if (name.indexOf('.json') > 0) {
            console.log("going to process " + name);
            processOwlFile(dir, name, outdir, templatePath, buildType, dir,project)
            console.log("processed " + name);
        }
    })
}

function main(){
    var pjson = require(join(__dirname, "../package.json"));
    var version = (pjson.version);
    console.log("owl version:" + version );

    var configFile = resolve(cwd,"owlconfig.json");
    // if (process.argv.length > 2) {
    //     configFile = resolve(cwd, process.argv[2]);
    // }


    var content = fs.readFileSync(configFile, {encoding: 'utf-8'})
    var owlconfig = JSON.parse(content)
    var inPath = owlconfig.models;
    var outPath = owlconfig.generatedApps
    var templatePath = owlconfig.templates
    var buildType = owlconfig.buildType;
    var project = owlconfig.project;
    buildProperties = resolve(cwd,owlconfig.buildProperties);
    libpath = resolve(cwd,owlconfig.libpath);
    templatePath = resolve(cwd, templatePath);
    var fulloutPath = resolve(cwd,outPath);

    console.log("after read config");

    console.log("inPath=",inPath);
    console.log("outPath=",outPath);
    console.log("templatePath=",templatePath);
    console.log("buildType=",buildType);
    console.log("project=",project);
    console.log("fulloutPath",fulloutPath);

    mkdir(fulloutPath);



    var inputPattern = null;
    if(process.argv.length>2){
        inputPattern = process.argv[2];
        console.log("compiling" + inputPattern);
    }

    if(inputPattern){
        if(isDirectory(resolve(cwd,inPath,inputPattern))){
            let inDir = resolve(cwd,inPath,inputPattern);
            let outDir = resolve(fulloutPath,inputPattern);
            processInputDir(inDir, outDir, templatePath, buildType,project);
            return;
        }
        else if (inputPattern.indexOf('.json') > 0) {
            let inDir = dirname(resolve(cwd,inPath,inputPattern));
            let name =basename(resolve(cwd,inPath,inputPattern));
            let outDir = dirname(resolve(fulloutPath,inputPattern));
            console.log("inDir",inDir,"name",name,"outDir",outDir);
            mkdir(outDir);
            processOwlFile(inDir, name, outDir, templatePath, buildType, inDir, project)
            console.log("processed " + name);
            return;
        }
    }
    else{
        processInputDir(inPath, fulloutPath, templatePath, buildType,project);
    }
}

main();



