/**
 * Settings
 * Turn on/off build features
 */
var settings = {
    clean: true,
    scripts: true,
    styles: true,
    copy: true,
    reload: true
};


/**
 * Paths to project folders
 */
var paths = {
    input: 'src/',
    output: 'dist/',
    scripts: {
        input: 'src/js/*.js',
        output: 'dist/js/'
    },
    styles: {
        input: 'src/scss/*.scss',
        output: 'dist/css/'
    },
    copy: {
        input: [
            'src/*.html',
//            'src/.htaccess',
            'src/{img,font}/**/*',
            'node_modules/@fortawesome/fontawesome-free/*fonts/**/*'
        ],
        output: 'dist/'
    },
    reload: './dist/'
};


/**
 * Template for banner to add to file headers
 */

var banner = {
    main:
        '/*!' +
        ' <%= package.name %> v<%= package.version %>' +
        ' | (c) ' + new Date().getFullYear() + ' <%= package.author.name %>' +
        ' | <%= package.license %> License' +
        ' | <%= package.repository.url %>' +
        ' */\n'
};


/**
 * Gulp Packages
 */
// General
var {src, dest, watch, series, parallel} = require('gulp');
var del = require('del');
var flatmap = require('gulp-flatmap');
var lazypipe = require('lazypipe');
var rename = require('gulp-rename');
var header = require('gulp-header');
var package = require('./package.json');

// Scripts
var concat = require('gulp-concat');
var uglify = require('gulp-terser');
var optimizejs = require('gulp-optimize-js');

// Styles
var sass = require('gulp-sass')(require('node-sass'));
var postcss = require('gulp-postcss');
var prefix = require('autoprefixer');
var minify = require('cssnano');
var tildeImporter = require('node-sass-tilde-importer');

// BrowserSync
var browserSync = require('browser-sync');


/**
 * Gulp Tasks
 */
// Remove pre-existing content from output folders
var cleanDist = function (done) {

    // Make sure this feature is activated before running
    if (!settings.clean) return done();

    // Clean the dist folder
    del.sync([
        paths.output
    ]);

    // Signal completion
    return done();

};

// Repeated JavaScript tasks
var jsTasks = lazypipe()
    .pipe(header, banner.main, {package: package})
    .pipe(optimizejs)
    .pipe(dest, paths.scripts.output)
    .pipe(rename, {suffix: '.min'})
    .pipe(uglify)
    .pipe(optimizejs)
    .pipe(header, banner.main, {package: package})
    .pipe(dest, paths.scripts.output);

// minify, and concatenate scripts
var buildScripts = function (done) {
    // Make sure this feature is activated before running
    if (!settings.scripts) return done();

    // Run tasks on script files
    return src(paths.scripts.input)
        .pipe(flatmap(function(stream, file) {

            // If the file is a directory
            if (file.isDirectory()) {

                // Setup a suffix variable
                var suffix = '';

                // If separate polyfill files enabled
                if (settings.polyfills) {

                    // Update the suffix
                    suffix = '.polyfills';

                    // Grab files that aren't polyfills, concatenate them, and process them
                    src([file.path + '/*.js', '!' + file.path + '/*' + paths.scripts.polyfills])
                        .pipe(concat(file.relative + '.js'))
                        .pipe(jsTasks());

                }

                // Grab all files and concatenate them
                // If separate polyfills enabled, this will have .polyfills in the filename
                src(file.path + '/*.js')
                    .pipe(concat(file.relative + suffix + '.js'))
                    .pipe(jsTasks());

                return stream;

            }

            // Otherwise, process the file
            return stream.pipe(jsTasks());

        }));

};

// Process, and minify Sass files
var buildStyles = function (done) {
    // Make sure this feature is activated before running
    if (!settings.styles) return done();

    // Run tasks on all Sass files
    return src(paths.styles.input)
        .pipe(sass({
            importer: tildeImporter,
            outputStyle: 'expanded',
            sourceComments: true
        }))
        .pipe(postcss([
            prefix({
                cascade: true,
                remove: true
            })
        ]))
        .pipe(header(banner.main, {package: package}))
        .pipe(dest(paths.styles.output))
        .pipe(rename({suffix: '.min'}))
        .pipe(postcss([
            minify({
                discardComments: {
                    removeAll: true
                }
            })
        ]))
        .pipe(dest(paths.styles.output));

};

// Copy static files into output folder
var copyFiles = function (done) {

    // Make sure this feature is activated before running
    if (!settings.copy) return done();

    // Copy static files
    return src(paths.copy.input)
        .pipe(dest(paths.copy.output));

};

// Watch for changes to the src directory
var startServer = function (done) {
    // Make sure this feature is activated before running
    if (!settings.reload) return done();

    // Initialize BrowserSync
    browserSync.init({
        server: {
            baseDir: paths.reload
        }
    });

    // Signal completion
    done();

};

// Reload the browser when files change
var reloadBrowser = function (done) {
    if (!settings.reload) return done();
    browserSync.reload();
    done();
};

// Watch for changes
var watchSource = function (done) {
    watch(paths.input, series(exports.default, reloadBrowser));
    done();
};


/**
 * Export Tasks
 */
// Default task
// gulp
exports.default = series(
    cleanDist,
    parallel(
        buildScripts,
        buildStyles,
        copyFiles
    )
);

// Watch and reload
// gulp watch
exports.watch = series(
    exports.default,
    startServer,
    watchSource
);