/*
 * Stairs
 * Copyright 2017 (c) Mark van Renswoude
 *
 * https://git.x2software.net/pub/Stairs
*/
'use strict';

const gulp = require('gulp');
const htmlmin = require('gulp-htmlmin');
const cppstringify = require('./gulp-cppstringify');
const fs = require('fs');
const plumber = require('gulp-plumber');
const sass = require('gulp-sass');
const cleanCSS = require('gulp-clean-css');
const watch = require('gulp-debounced-watch');
const uglify = require('gulp-uglify');
const concat = require('gulp-concat');
const print = require('gulp-print');
const path = require('path');
const gzip = require('gulp-gzip');


const config = {
  assetsPath: 'web/',
  distPath: 'web/dist/',
  outputPath: 'src/assets/',

  firmwareArtifact: '.pioenvs/esp12e/firmware.bin',
  firmwareOutputPath: 'bin/'
};


const HTMLMap = {
  'index.html': 'Index'
};

const JSMap = {
  'bundle.js': 'BundleJS'
};

const CSSMap = {
  'bundle.css': 'BundleCSS'
};


// There is an issue in the AsyncWebServer where it's apparantly running
// out of memory on simultaneous requests. We'll work around it by
// merging all the JS into one big file.
//
// https://github.com/me-no-dev/ESPAsyncWebServer/issues/256
const JSSrc = [
  'node_modules/axios/dist/axios.min.js',
  'node_modules/vue/dist/vue.min.js',
  'node_modules/vue-i18n/dist/vue-i18n.min.js',
  'web/lang.js',
  'web/app.js'
];

const SCSSSrc = [
  'web/site.scss'
]




gulp.task('default',
  [
    'embedAssets'
  ],
  function(){});


gulp.task('watch',
  [
    'compileScss',
    'compileJS'
  ],
  function()
  {
    watch(config.assetsPath + '*.scss', function() { gulp.start('compileScss'); });
    watch(config.assetsPath + '*.js', function() { gulp.start('compileJS'); });
  });



gulp.task('embedHTML', function()
{
  return gulp.src(config.assetsPath + '*.html')
    .pipe(print(function(filepath) { return 'HTML: ' + filepath }))
    .pipe(htmlmin({
      collapseWhitespace: true,
      removeComments: true,
      minifyCSS: true,
      minifyJS: true
    }))
    .pipe(gzip({ append: false }))
    .pipe(cppstringify('html.h', {
      headerDefineName: '__assets_html',
      map: HTMLMap,
      byteArray: true
    }))
    .pipe(gulp.dest(config.outputPath));
});


gulp.task('compileScss', function()
{
  return gulp.src(SCSSSrc)
    .pipe(plumber({
      errorHandler: function (error)
        {
          console.log(error.toString());
          this.emit('end');
      }}))
    .pipe(print(function(filepath) { return 'SCSS: ' + filepath }))
    .pipe(sass({
      includePaths: ['node_modules/milligram/src']
    }))
    .pipe(cleanCSS({compatibility: 'ie9'}))
    .pipe(concat('bundle.css'))
    .pipe(gulp.dest(config.distPath));
});


gulp.task('compileJS', function()
{
  return gulp.src(JSSrc)
    .pipe(plumber({
      errorHandler: function (error)
        {
          console.log(error.toString());
          this.emit('end');
      }}))
    .pipe(print(function(filepath) { return 'JS: ' + filepath }))
    .pipe(concat('bundle.js'))
    .pipe(uglify())
    .pipe(gulp.dest(config.distPath));
});


gulp.task('embedJS', ['compileJS'], function()
{
  return gulp.src([config.distPath + 'bundle.js'])
    .pipe(gzip({ append: false }))
    .pipe(cppstringify('js.h', {
      headerDefineName: '__assets_js',
      map: JSMap,
      byteArray: true
    }))
    .pipe(gulp.dest(config.outputPath));
});


gulp.task('embedCSS', ['compileScss'], function()
{
  return gulp.src([config.distPath + 'bundle.css'])
    .pipe(gzip({ append: false }))
    .pipe(cppstringify('css.h', {
      headerDefineName: '__embed_css',
      map: CSSMap,
      byteArray: true
    }))
    .pipe(gulp.dest(config.outputPath));
});



var version = false;
function getVersion(callback)
{
  if (version !== false)
  {
    callback(version);
    return;
  }

  var versionData = '';
  const cmd = spawn('gitversion');

  cmd.stdout.on('data', function(data)
  {
    versionData += data;
  });

  cmd.stderr.on('data', function(data)
  {
    console.log(data.toString().trim());
  });

  cmd.on('exit', function(code)
  {
    if (code != 0) return;

    var version = JSON.parse(versionData);
    callback(version);
  });
}


gulp.task('embedVersion', function(cb)
{
  getVersion(function(version)
  {
    var headerFile = "#ifndef __assets_version\r\n";
    headerFile += "#define __assets_version\r\n\r\n";
    headerFile += "const uint8_t VersionMajor = " + version.Major + ";\r\n";
    headerFile += "const uint8_t VersionMinor = " + version.Minor + ";\r\n";
    headerFile += "const uint8_t VersionPatch = " + version.Patch + ";\r\n";
    headerFile += "const uint8_t VersionMetadata = " + (version.BuildMetaData ? version.BuildMetaData : '0') + ";\r\n";

    headerFile += "const char VersionBranch[] = \"" + version.BranchName + "\";\r\n";

    headerFile += "const char VersionSemVer[] = \"" + version.SemVer + "\";\r\n";
    headerFile += "const char VersionFullSemVer[] = \"" + version.FullSemVer + "\";\r\n";

    headerFile += "const char VersionCommitDate[] = \"" + version.CommitDate + "\";\r\n";

    headerFile += "\r\n#endif\r\n";

    fs.writeFile(config.outputPath + 'version.h', headerFile, function(err)
    {
      if (err) throw err;
      cb();
    });
  });
});


gulp.task('copyBinary', function(cb)
{
  if (!fs.existsSync(config.firmwareOutputPath))
    fs.mkdirSync(config.firmwareOutputPath, '0777', true);

  getVersion(function(version)
  {
    var target = path.join(config.firmwareOutputPath, version.FullSemVer + '.bin');
    console.log('Target: ' + target);

    var reader = fs.createReadStream(config.firmwareArtifact);
    reader.pipe(fs.createWriteStream(target));
    reader.on('end', cb);
  });
});


gulp.task('embedAssets', ['embedHTML', 'embedJS', 'embedCSS', 'embedVersion'], function() { })



// PlatformIO
const spawn = require('child_process').spawn;
const argv = require('yargs').argv;

var platformio = function(target)
{
  var args = ['run'];
  if ("e" in argv)
  {
    args.push('-e');
    args.push(argv.e);
  }

  if ("p" in argv)
  {
    args.push('--upload-port');
    args.push(argv.p);
  }

  if (target)
  {
    args.push('-t');
    args.push(target);
  }

  const cmd = spawn('platformio', args);
  cmd.stdout.on('data', function(data)
  {
    console.log(data.toString().trim());
  });

  cmd.stderr.on('data', function(data)
  {
    console.log(data.toString().trim());
  });

  cmd.on('exit', function(code)
  {
    if (code != 0) return;
    gulp.start('copyBinary');
  });
}

gulp.task('upload', ['embedHTML', 'embedAssets'], function() { platformio('upload'); });
gulp.task('build', ['embedHTML', 'embedAssets'], function() { platformio(false); });