/// <binding AfterBuild='_vsEventBuildCompleted' ProjectOpened='_vsEventProjectOpened' />
var gulp = require('gulp');
var concat = require('gulp-concat');
var typescript = require('gulp-typescript');
var sourcemaps = require('gulp-sourcemaps');
var fs = require('fs');
var path = require('path');
var gulpIgnore = require('gulp-ignore');
var uglify = require('gulp-uglify');
var templateCache = require("gulp-angular-templatecache"); // put html templates into the template cache
var streamqueue = require('streamqueue'); // merge pipes in order. used to merge tsc and template output
var header = require("gulp-header"); // add console.log("Loading module xxx") into each module bundle
var footer = require("gulp-footer"); // add console.log("Module loadet xxx") into each module bundle
var gutil = require('gulp-util'); // uses Noop
var replace = require('gulp-replace'); // used to "remove modules" from InternalDependencies.ts
var argv = require('yargs').argv;
var gulpif = require('gulp-if');
var fc2json = require('gulp-file-contents-to-json');
var embedTemplates = require('gulp-angular-embed-templates');
var merge = require('merge-stream');
var merge2 = require('merge2');
var rename = require('gulp-rename');
var gap = require('gulp-append-prepend');
var bundleconfig = require("./bundleconfig.gulp.json");
var compilerconfig = require("./compilerconfig.gulp.json");
var cleanCSS = require('gulp-clean-css');
var sass = require('gulp-sass');
var concatCss = require('gulp-concat-css');

var exec = require('child_process').exec;

//var cssmin = require("gulp-cssmin"),
//    htmlmin = require("gulp-htmlmin"),
//    jsmin = require("gulp-jsmin"),
//    del = require("del"),
//    rename = require('gulp-rename'),
//    bundleconfig = require("./bundleconfig.json");

//var sass = require('gulp-sass');
//var cleanCss = require('gulp-clean-css');
//var es = require("event-stream");
//var livereload = require('gulp-livereload');
//var wait = require('gulp-wait');

var lazyloadModules = [
    'Kanban',
    'DepartmentUsers',
    'EditorRevision',
    'ProfileProgress',
    'Gamification',
    'Birthday',
    'Poll',
    'CanteenMenu',
    'Currentmenu',
    'Manual',
    'Employees',
    'Webform',    
    'LightningPages',
    'BusinessApps',
    'ProjectSpace',
    'CourseManagement',
    'Helpdesk',
    'LiveTiles'
];
var modulesNotToBundleInAppJs = Array.from(lazyloadModules, moduleName => "!./Modules/" + moduleName + "/**"); // returns: ["!./Modules/Kanban/**", "!./Modules/Poll/**", ... ]

var folderDir = 'Modules';
var folders = getFolders(folderDir);
var lazyModuleConfigs = folders.filter(function (folder) {
    if (lazyloadModules.indexOf(folder) > -1 && fs.existsSync("./Modules/" + folder + "/Module.json")) {
        return true; // is lazyloadModule
    }
    else {
        return false; // is not lazyloadModule
    }
}).map(function (lazyFolder) {
    var moduleConfig = JSON.parse(fs.readFileSync("./Modules/" + lazyFolder + "/Module.json", { encoding: "utf8" }).trim());
    return moduleConfig.Scripts.map(function (scriptObj) {
        return { name: scriptObj.Selectors[0], files: scriptObj.Srcs };
    })[0];
});

gulp.task('_vsEventProjectOpened', function () {
    if (!fs.existsSync("c:\\NoRunByEvent")) {
        gulp.start("watch-typescript-modules");
        gulp.start("watch-bundleconfig");
    }
});
gulp.task('_vsEventBuildCompleted', function () {
    if (!fs.existsSync("c:\\NoRunByEvent"))
        return gulp.start("default");
});

gulp.task('testGulp', function (cb) {
    console.log('Testing gulp tasks. This might take a few seconds.');
    exec('gulp --version',
        function (error, stdout, stderr) {
            console.log('gulp --version');
            console.log(stdout);

            exec('node --version',
                function (error, stdout, stderr) {
                    console.log('node --version');
                    console.log(stdout);

                    exec('npm --version',
                        function (error, stdout, stderr) {
                            console.log('npm --version');
                            console.log(stdout);

                            exec('gulp --gulpfile ./gulpfilePOC.js',
                                function (error, stdout, stderr) {
                                    console.log('gulpfilePOC.js');
                                    console.log(stdout);
                                    cb();
                                    if (error) {
                                        console.log(error, stderr);
                                    }
                                }
                            );
                        });
                });
        });
});

function compileTypescript(src) {
    return gulp.src(src)
        .pipe(typescript({
            sortOutput: true,
            emitError: false,
            noLibCheck: true,
            removeComments: true
            //target: 'ES6'
        }))
        .pipe(embedTemplates({
            basePath: "./Modules/",
            skipTemplates: function (templatePath, fileContext) {
                return templatePath.toLowerCase().indexOf('/dialogs/') > -1
                    || templatePath.toLowerCase().indexOf('/viewtemplates/') > -1
                    || templatePath.toLowerCase().indexOf('/base/') > -1
                    || templatePath.toLowerCase().indexOf('=') > -1;
            },
            minimize: {
                empty: true
            }
        }))
        .pipe(concat("tempfile.js"))
        .pipe(gulpif(argv.release, uglify()));
}

function compileTemplates(src, module) {    
    if (!module)
        module = "Wizdom365";
    return gulp.src(src).pipe(templateCache({ module: module }));
    
}

//function compileAppJsBundle(src, destinationDir, filename) {
//    var templateSources = ['./Modules/**/ViewTemplates/**/*.html', './Modules/**/ViewTemplatesV2/**/*.html'];
//    var templateTask = gulp.src(templateSources.concat(src))
//        .pipe(templateCache({ module: "Wizdom365" }));


//    var tsSources = ['./Modules/**/*.ts', './Base/Scripts/typings/**/*.d.ts'];
//    var tsTask = gulp.src(tsSources.concat(src))
//        .pipe(typescript({
//            sortOutput: true,
//            emitError: false,
//            noLibCheck: true,
//            removeComments: true
//        }))
//        .pipe(embedTemplates({
//            basePath: "./Modules/",
//            skipTemplates: function (templatePath, fileContext) {
//                return templatePath.toLowerCase().indexOf('/dialogs/') > -1
//                    || templatePath.toLowerCase().indexOf('/viewtemplates/') > -1
//                    || templatePath.toLowerCase().indexOf('/base/') > -1
//                    || templatePath.toLowerCase().indexOf('=') > -1;
//            },
//            minimize: {
//                empty: true
//            }
//        }))
//        .pipe(concat(filename))
//        .pipe(gulpif(argv.release, uglify())) // only uglify if runing gulp like: "gulp --release"            

//    return merge2(tsTask, templateTask).pipe(concat(filename)).pipe(gulp.dest(destinationDir));
//}

function getFolders(dir) {
    return fs.readdirSync(dir)
        .filter(function (file) {
            return fs.statSync(path.join(dir, file)).isDirectory();
        });
}

gulp.task('compile-ts-modules', function () {
    var folderDir = 'Modules';
    var folders = getFolders(folderDir);
    var tasks = folders
        .filter(function (folder) {
            if (lazyloadModules.indexOf(folder) > -1) {
                if (argv.module) { // if the parameter module is set, then we check if that module is a lazyloadModule and only compile that one
                    return argv.module === folder;
                }
                else
                    return true; // is lazyloadModule
            }
            else
                return false; // is not lazyloadModule
        })
        .map(function (folder) {
            gutil.log("Compiling module '" + folder + "'");
            var patterns =
                [
                    path.join(folderDir, folder, "/**/*.ts"),
                    './Base/Scripts/typings/**/*.d.ts',
                    '!/**/*.admin.ts',
                    '!/**/*.editmode.ts',
                    '!/**/Notifications/**'
                ];            
            var tsTask = gulp.src(patterns)
                .pipe(typescript({
                    sortOutput: true,
                    emitError: false,
                    noLibCheck: true,
                    removeComments: true
                }))
                .pipe(embedTemplates({
                    basePath: "./Modules/",
                    skipTemplates: function (templatePath, fileContext) {
                        return templatePath.toLowerCase().indexOf('/dialogs/') > -1
                            || templatePath.toLowerCase().indexOf('/viewtemplates/') > -1
                            || templatePath.toLowerCase().indexOf('/base/') > -1
                            || templatePath.toLowerCase().indexOf('=') > -1;
                    },
                    minimize: {
                        empty: true
                    }
                }))
                .pipe(gulpif(argv.release, uglify())) // only uglify if runing gulp like: "gulp --release"
                .pipe(concat(folder + '.js'))
                .pipe(gap.appendText('angular.module("Wizdom365").requires.push("Wizdom365.' + folder + '");'));

            var templateTask = gulp.src(path.join(folderDir, folder, "**/ViewTemplates/*.html"))
                .pipe(templateCache({ module: "Wizdom365", root: folder + "/", templateBody: 'if($templateCache.get(\'<%= url %>\') == null) $templateCache.put(\'<%= url %>\',\'<%= contents %>\');' }));

            return merge2(tsTask, templateTask).pipe(concat(folder + '.js')).pipe(gulp.dest(path.join('./Base/Bundles/Modules')));
        });
    return merge2(tasks);
});

gulp.task('compile-ts-app', function () {
    
    var tsSources = [        
        './Modules/**/*.ts',        
        ...modulesNotToBundleInAppJs,        
        './Base/Scripts/typings/**/*.d.ts',
        '!/**/*.admin.ts',
        '!/**/*.editmode.ts',
        '!/**/WebapiServiceSaaS.ts'
    ];
    var templateSources = [
        './Modules/**/ViewTemplates/**/*.html',
        './Modules/**/ViewTemplatesV2/**/*.html',
        ...modulesNotToBundleInAppJs        
    ];
    return merge2(compileTypescript(tsSources), compileTemplates(templateSources, "Wizdom365")).pipe(replace("[\"this-here-will-be-replaced-with-lazyload-array-by-gulp\"]", JSON.stringify(lazyModuleConfigs)))
        .pipe(concat('app.js')).pipe(gulp.dest('./Base/Bundles/'));  
});
gulp.task('compile-ts-appSaaS', function () {

    var tsSources = [
        './Modules/**/*.ts',
        ...modulesNotToBundleInAppJs,
        './Base/Scripts/typings/**/*.d.ts',
        '!/**/*.admin.ts',
        '!/**/*.editmode.ts',
        '!/**/WebapiService.ts'
    ];
    var templateSources = [
        './Modules/**/ViewTemplates/**/*.html',
        './Modules/**/ViewTemplatesV2/**/*.html',
        ...modulesNotToBundleInAppJs
    ];
    return merge2(compileTypescript(tsSources), compileTemplates(templateSources, "Wizdom365")).pipe(replace("[\"this-here-will-be-replaced-with-lazyload-array-by-gulp\"]", JSON.stringify(lazyModuleConfigs)))
        .pipe(concat('AppSaaS.js')).pipe(gulp.dest('./Base/Bundles/'));
});
gulp.task('compile-ts-signup', function () {

    var tsSources = [
        './Base/Signup/**/*.ts'
        //'./Modules/Wizdom365/Directives/Spinner.ts',
        //'./Modules/Wizdom365/Directives/PrincipalPicker.ts',
        //'./Modules/Wizdom365/Services/WebapiServiceSaaS.ts'        
    ];
    var templateSources = [
        './Base/Signup/**/*.html'        
    ];
    return merge2(compileTypescript(tsSources), compileTemplates(templateSources, "Wizdom365Signup"))
        .pipe(concat('Signup.js')).pipe(gulp.dest('./Base/Bundles/'));
});
gulp.task('compile-ts-appCore', function () {
    var tsSources = [
        './Modules/**/*.ts',
        './Base/Scripts/typings/**/*.d.ts',
        '!/**/*.admin.ts',
        '!/**/*.editmode.ts'
    ];
    return compileTypescript(tsSources)
        .pipe(concat('appCore.js'))
        .pipe(gulp.dest('./Base/Bundles/'));    
});
gulp.task('compile-ts-appFull', function () {    
    var tsSources = [
        './Modules/**/*.ts',
        './Base/Scripts/typings/**/*.d.ts',
        '!/**/*.admin.ts',
        '!/**/*.editmode.ts'
    ];
    var templateSources = [
        './Modules/**/ViewTemplates/**/*.html',
        './Modules/**/ViewTemplatesV2/**/*.html'
    ];
    return merge2(compileTypescript(tsSources), compileTemplates(templateSources, "Wizdom365"))
        .pipe(concat('appFull.js'))
        .pipe(gulp.dest('./Base/Bundles/'));    
});

gulp.task('compile-ts-appAdmin', function () {
    var tsSources = [
        './Modules/**/*.admin.ts',
        './Base/**/*.ts',
        './Base/Scripts/typings/**/*.d.ts'
    ];
    return compileTypescript(tsSources)
        .pipe(concat('app.admin.js'))
        .pipe(gulp.dest('./Base/Bundles/'));    
});

gulp.task('compile-ts-appEditMode', function () {
    var tsSources = [
        './Modules/**/*.editmode.ts',
        './Base/Scripts/typings/**/*.d.ts'
    ];
    return compileTypescript(tsSources)
        .pipe(concat('app.editmode.js'))
        .pipe(gulp.dest('./Base/Bundles/')); 
});

// bsc> this is the task TFS will run on build
gulp.task('default', [
    'compile-ts-app',
    'compile-ts-appSaaS',
    'compile-ts-appCore',
    'compile-ts-appFull',
    'compile-ts-appAdmin',
    'compile-ts-appEditMode',
    'compile-ts-modules',
    'compile-ts-signup',
    'compile-scss',
    'bundle-css',
    'bundle-js',
    'templatesToJson'
]);

gulp.task('watch-typescript-modules', function () {
    return gulp.watch(['Modules/**/*.ts', 'Base/**/*.ts', 'Modules/**/*.html'], function (file) {
        if (file.path.indexOf(".editmode.ts") > 0)
            gulp.start('compile-ts-appEditMode');
        else if (file.path.indexOf(".admin.ts") > 0 || file.path.indexOf("\\Base\\") > 0) {
            gulp.start('compile-ts-appAdmin');
            gulp.start('compile-ts-signup');
        }
        else if (file.path.indexOf("GUI.Web\\Modules") > 0) {
            var moduleStartPath = file.path.substring(file.path.indexOf("GUI.Web\\Modules") + 16); // returns: CourseManagement\Directives\Overview.ts
            var moduleFolder = moduleStartPath.substring(0, moduleStartPath.indexOf("\\")); // returns: CourseManagement                                  

            if (lazyloadModules.indexOf(moduleFolder) > -1) {
                argv.module = moduleFolder;
                gulp.start('compile-ts-modules');
            }
            else { // if not lazyloaded, then we compile app.js
                gulp.start('compile-ts-app');
                gulp.start('compile-ts-appSaaS');
            }
        }
        //else if (file.path.indexOf("\\Base/Signup/") > 0 || file.path.indexOf("\\Base\\") > 0)
        //    gulp.start('compile-ts-appAdmin');
        else {
            gutil.log("Unwatched file changed");        
        }
    });
});

// bsc> this task will also be run by TFS. Its not needed for local development
gulp.task('templatesToJson', function () {
    return gulp.src('./Modules/**/*.html')
        .pipe(fc2json('TemplateFiles.json'))
        .pipe(gulp.dest('./app_data'));
});

gulp.task("watch-bundleconfig", function () {
    getBundles(".js").forEach(function (bundle) {
        gulp.watch(bundle.inputFiles, ["bundle-js"]);
    });

    getBundles(".css").forEach(function (bundle) {
        gulp.watch(bundle.inputFiles, ["bundle-css"]);
    });
});

gulp.task("bundle-js", function () {
    var tasks = getBundles(".js").map(function (bundle) {
        return gulp.src(bundle.inputFiles, { base: "." })
            .pipe(concat(bundle.outputFileName))
            .pipe(gulp.dest("."))
            .pipe(uglify({ preserveComments: 'license' })) //https://github.com/terinjokes/gulp-uglify/blob/a9c55b9e6ff99a8d395fb1e82d0050c11c256483/minifier.js#L32-L41            
            .pipe(rename({ suffix: '.min' }))
            .pipe(sourcemaps.write('maps'))
            .pipe(gulp.dest("."));
    });
    return merge(tasks);
});

gulp.task("bundle-css", ["compile-scss"], function () {
    var tasks = getBundles(".css").map(function (bundle) {
        return gulp.src(bundle.inputFiles, { base: "." })
            .pipe(concatCss(bundle.outputFileName))    
            .pipe(gulp.dest("."))
            .pipe(cleanCSS({ compatibility: 'ie10' }))
            .pipe(rename({ suffix: '.min' }))
            .pipe(gulp.dest("."));
    });
    return merge(tasks);
});

gulp.task("compile-scss", function () {
    var tasks = compilerconfig.map(function (entry) {
        return gulp.src(entry.inputFile)
            .pipe(sass().on('error', sass.logError))
            .pipe(rename(entry.outputFile))
            .pipe(header('\ufeff'))
            .pipe(gulp.dest("."))
            .pipe(cleanCSS({ compatibility: 'ie10' }))
            .pipe(rename({ suffix: '.min' }))
            .pipe(gulp.dest("."));
    });
    return merge(tasks);
});

function getBundles(extension) {
    return bundleconfig.filter(function (bundle) {
        return new RegExp(`${extension}$`).test(bundle.outputFileName);
    });
}