text: 'use strict';
  
  /* jshint node: true, mocha: true */
  /* global suiteSetup */
  
  var assert = require('chai').assert;
  var path = require('path');
  var fs = require('fs');
  var helper = require('helper');
  var AdmZip = require('adm-zip');
  var jsdom = require('jsdom').jsdom;
  
  function checkLayoutsJSON(zipPath, expectedArr) {
    var zip = new AdmZip(zipPath);
    var entry = zip.getEntry('js/settings/layouts.json');
    var actualArr = JSON.parse(zip.readAsText(entry));
  
    actualArr.forEach(function(layout) {
      assert.isTrue(
        !!layout.dictFileSize,
        'Expect layout contain to non-zero dictFileSize, id=' + layout.id);
      delete layout.dictFileSize;
    });
  
    expectedArr.forEach(function(layout) {
      delete layout.dictFileSize;
    });
  
    assert.deepEqual(actualArr, expectedArr);
  }
  
  suite('Keyboard layouts building tests', function() {
    suiteSetup(helper.cleanupWorkspace);
    teardown(helper.cleanupWorkspace);
  
    // default make -- build with selected layouts and dictionaries
    test('APP=keyboard make', function(done) {
      var cmd = 'APP=keyboard make';
      helper.exec(cmd, function(error, stdout, stderr) {
        helper.checkError(error, stdout, stderr);
  
        var config = JSON.parse(process.env.BUILD_CONFIG);
        var layoutIds = ['ar',
                         'bn-Avro',
                         'bn-Probhat',
                         'de',
                         'de-Neo',
                         'dz-BT',
                         'en',
                         'en-Colemak',
                         'en-Dvorak',
                         'en-Neo',
                         'eo',
                         'es',
                         'es-Americas',
                         'fa',
                         'fr',
                         'fr-CA',
                         'fr-CH',
                         'fr-Dvorak-bepo',
                         'he',
                         'hi',
                         'ig',
                         'ko',
                         'mk',
                         'my',
                         'pl',
                         'pt-BR',
                         'ta',
                         'te',
                         'th',
                         'vi-Qwerty',
                         'vi-Telex',
                         'vi-Typewriter',
                         'wo',
                         'zh-Hans-Pinyin'];
        var zipPath = path.join(process.cwd(), 'profile',
          'webapps', 'keyboard.gaiamobile.org', 'application.zip');
        var appDirPath = config.GAIA_DIR + '/apps/keyboard';
  
        var layouts = layoutIds.map(function(layout) {
          return 'js/layouts/' + layout + '.js';
        });
  
        // Unfortunately we can only whilelist files here because we shouldn't
        // throw error if excluded files are missing (e.g. README).
        var imes = [
          'js/imes/jshangul/jshangul.js',
          'js/imes/jspinyin/empinyin_files.data',
          'js/imes/jspinyin/empinyin_files.js',
          'js/imes/jspinyin/jspinyin.js',
          'js/imes/jspinyin/libpinyin.js',
          'js/imes/jspinyin/worker.js',
          'js/imes/latin/latin.js',
          'js/imes/latin/predictions.js',
          'js/imes/latin/worker.js'
        ];
  
        var dicts = [
          'js/imes/latin/dictionaries/de.dict',
          'js/imes/latin/dictionaries/en_us.dict',
          'js/imes/latin/dictionaries/es.dict',
          'js/imes/latin/dictionaries/fr.dict',
          'js/imes/latin/dictionaries/pl.dict',
          'js/imes/latin/dictionaries/pt_br.dict'
        ];
  
        var checkList = [].concat(layouts, imes, dicts);
        checkList.forEach(function(path) {
          helper.checkFileInZip(zipPath, path, appDirPath + '/' + path);
        });
  
        // Verify inputs entry in manifest
        var zip = new AdmZip(zipPath);
        var entry = zip.getEntry('manifest.webapp');
        var manifest = JSON.parse(zip.readAsText(entry));
        var inputKeysInManifest = Object.keys(manifest.inputs);
  
        assert.deepEqual(inputKeysInManifest.sort(),
                         [].concat(layoutIds, 'number', 'emoji').sort());
  
        // Verify dictionary config
        var dictJSON = JSON.parse(fs.readFileSync(
              appDirPath +
              '/test/build/integration/resources/' +
              'default-make-layouts.json'));
  
        checkLayoutsJSON(zipPath, dictJSON);
  
        done();
      });
    });
  
    // Build with all layouts and dictionaries
    test('APP=keyboard GAIA_KEYBOARD_LAYOUTS=* make', function(done) {
      var cmd = 'APP=keyboard GAIA_KEYBOARD_LAYOUTS=* make';
      helper.exec(cmd, function(error, stdout, stderr) {
        helper.checkError(error, stdout, stderr);
  
        var config = JSON.parse(process.env.BUILD_CONFIG);
        var zipPath = path.join(process.cwd(), 'profile',
          'webapps', 'keyboard.gaiamobile.org', 'application.zip');
        var appDirPath = config.GAIA_DIR + '/apps/keyboard';
        var layoutIds =
          fs.readdirSync(appDirPath + '/js/layouts').filter(function(filename) {
            return (path.extname(filename) === '.js');
          }).map(function(filename) {
            return path.basename(filename, '.js');
          }).filter(function(layoutId) {
            // Exclude noIncludeInExpandLayoutIdSet layouts
            return (['emoji'].indexOf(layoutId) === -1);
          });
  
        var layouts = layoutIds.map(function(layout) {
          return 'js/layouts/' + layout + '.js';
        });
  
        // Unfortunately we can only whilelist files here because we shouldn't
        // throw error if excluded files are missing (e.g. README).
  
        // For the sake of simplicity let's only check the main scripts.
        var imes = [
          'js/imes/handwriting/handwriting.js',
          'js/imes/india/india.js',
          'js/imes/jshangul/jshangul.js',
          'js/imes/jskanji/jskanji.js',
          'js/imes/jspinyin/jspinyin.js',
          'js/imes/latin/latin.js',
          'js/imes/vietnamese/vietnamese.js',
          'js/imes/myanmar/myanmar.js'
        ];
  
        var dicts = [
          'js/imes/latin/dictionaries/bg.dict',
          'js/imes/latin/dictionaries/bs.dict',
          'js/imes/latin/dictionaries/ca.dict',
          'js/imes/latin/dictionaries/cs.dict',
          'js/imes/latin/dictionaries/da.dict',
          'js/imes/latin/dictionaries/de.dict',
          'js/imes/latin/dictionaries/el.dict',
          'js/imes/latin/dictionaries/en_gb.dict',
          'js/imes/latin/dictionaries/en_us.dict',
          'js/imes/latin/dictionaries/es.dict',
          'js/imes/latin/dictionaries/eu.dict',
          'js/imes/latin/dictionaries/fr.dict',
          'js/imes/latin/dictionaries/ga.dict',
          'js/imes/latin/dictionaries/gd.dict',
          'js/imes/latin/dictionaries/gl.dict',
          'js/imes/latin/dictionaries/gv.dict',
          'js/imes/latin/dictionaries/hr.dict',
          'js/imes/latin/dictionaries/hu.dict',
          'js/imes/latin/dictionaries/it.dict',
          'js/imes/latin/dictionaries/lt.dict',
          'js/imes/latin/dictionaries/lv.dict',
          'js/imes/latin/dictionaries/nb.dict',
          'js/imes/latin/dictionaries/nl.dict',
          'js/imes/latin/dictionaries/pl.dict',
          'js/imes/latin/dictionaries/pt_br.dict',
          'js/imes/latin/dictionaries/pt_pt.dict',
          'js/imes/latin/dictionaries/ro.dict',
          'js/imes/latin/dictionaries/ru.dict',
          'js/imes/latin/dictionaries/sk.dict',
          'js/imes/latin/dictionaries/sq.dict',
          'js/imes/latin/dictionaries/sr-Cyrl.dict',
          'js/imes/latin/dictionaries/sr-Latn.dict',
          'js/imes/latin/dictionaries/sv.dict',
          'js/imes/latin/dictionaries/tr.dict',
          'js/imes/latin/dictionaries/af.dict'
        ];
  
        var checkList = [].concat(layouts, imes, dicts);
        checkList.forEach(function(path) {
          helper.checkFileInZip(zipPath, path, appDirPath + '/' + path);
        });
  
        // Verify inputs entry in manifest
        var zip = new AdmZip(zipPath);
        var entry = zip.getEntry('manifest.webapp');
        var manifest = JSON.parse(zip.readAsText(entry));
        var inputKeysInManifest = Object.keys(manifest.inputs);
  
        assert.deepEqual(inputKeysInManifest.sort(),
                         [].concat(layoutIds, 'number', 'emoji').sort());
  
        // Verify dictionary config
        var dictJSON = JSON.parse(fs.readFileSync(
              appDirPath +
              '/test/build/integration/resources/' +
              'all-layout-make-layouts.json'));
  
        checkLayoutsJSON(zipPath, dictJSON);
  
        done();
      });
    });
  
    // Build with all layouts with no dictionaries
    // (preload ko layout here to avoid empty check.)
    test('APP=keyboard GAIA_KEYBOARD_LAYOUTS=ko ' +
      'GAIA_KEYBOARD_DOWNLOADABLE_LAYOUTS=noPreloadDictRequired make',
    function(done) {
      var cmd = 'APP=keyboard GAIA_KEYBOARD_LAYOUTS=ko ' +
      'GAIA_KEYBOARD_DOWNLOADABLE_LAYOUTS=noPreloadDictRequired make';
      helper.exec(cmd, function(error, stdout, stderr) {
        helper.checkError(error, stdout, stderr);
  
        var config = JSON.parse(process.env.BUILD_CONFIG);
        var zipPath = path.join(process.cwd(), 'profile',
          'webapps', 'keyboard.gaiamobile.org', 'application.zip');
        var appDirPath = config.GAIA_DIR + '/apps/keyboard';
  
        // For this test, we verify there isn't any dictionary
        // in the zip.
        var zip = new AdmZip(zipPath);
        var entries = zip.getEntries();
        var imePath = 'js/imes';
        var sizeLimit = (1 << 10) * 100; // 100K
        entries.forEach(function(entry) {
          if (entry.entryName.substr(0, imePath.length) !== imePath) {
            return;
          }
  
          var fileSize = entry.getData().length;
          assert.isTrue(fileSize < sizeLimit,
            'IME file is larger than non-dictionary limit: ' + entry.entryName +
            ', size: ' + fileSize + ' bytes.');
        });
  
        // Verify dictionary config
        var dictJSON = JSON.parse(fs.readFileSync(
              appDirPath +
              '/test/build/integration/resources/' +
              'no-preload-dict-required-make-layouts.json'));
  
        checkLayoutsJSON(zipPath, dictJSON);
  
        done();
      });
    });
  
    // Build default layouts with only en dictionary, and extra IMEs
    test('APP=keyboard GAIA_KEYBOARD_LAYOUTS=en ' +
      'GAIA_KEYBOARD_DOWNLOADABLE_LAYOUTS=' +
      'en,pt-BR,es,de,fr,fr-CA,pl,ko,zh-Hans-Pinyin,en-Dvorak make',
    function(done) {
      var cmd = 'APP=keyboard GAIA_KEYBOARD_LAYOUTS=en ' +
        'GAIA_KEYBOARD_DOWNLOADABLE_LAYOUTS=' +
        'en,pt-BR,es,de,fr,fr-CA,pl,ko,zh-Hans-Pinyin,en-Dvorak make';
      helper.exec(cmd, function(error, stdout, stderr) {
        helper.checkError(error, stdout, stderr);
  
        var config = JSON.parse(process.env.BUILD_CONFIG);
        var zipPath = path.join(process.cwd(), 'profile',
          'webapps', 'keyboard.gaiamobile.org', 'application.zip');
        var appDirPath = config.GAIA_DIR + '/apps/keyboard';
        var layoutIds = config.GAIA_KEYBOARD_LAYOUTS.split(',').sort()
          .filter(function(layoutId) {
            // Exclude noIncludeInExpandLayoutIdSet layouts
            return (['emoji'].indexOf(layoutId) === -1);
          });
  
        var layouts = layoutIds.map(function(layout) {
          return 'js/layouts/' + layout + '.js';
        });
  
        // Unfortunately we can only whilelist files here because we shouldn't
        // throw error if excluded files are missing (e.g. README).
        var imes = [
          'js/imes/jshangul/jshangul.js',
          'js/imes/jspinyin/empinyin_files.data',
          'js/imes/jspinyin/empinyin_files.js',
          'js/imes/jspinyin/jspinyin.js',
          'js/imes/jspinyin/libpinyin.js',
          'js/imes/jspinyin/worker.js',
          'js/imes/latin/latin.js',
          'js/imes/latin/predictions.js',
          'js/imes/latin/worker.js'
        ];
  
        var dicts = [
          'js/imes/latin/dictionaries/es.dict',
          'js/imes/latin/dictionaries/fr.dict',
          'js/imes/latin/dictionaries/pl.dict',
          'js/imes/latin/dictionaries/pt_br.dict'
        ];
  
        var checkList = [].concat(layouts, imes);
        checkList.forEach(function(path) {
          helper.checkFileInZip(zipPath, path, appDirPath + '/' + path);
        });
  
        // Verify inputs entry in manifest
        var zip = new AdmZip(zipPath);
        var entry = zip.getEntry('manifest.webapp');
        var manifest = JSON.parse(zip.readAsText(entry));
        var inputKeysInManifest = Object.keys(manifest.inputs);
  
        // Only layouts with dictionaries should be declaried.
        // Noted that en-Dvorak use the same dictionary as en so it should also
        // be declaried.
        assert.deepEqual(inputKeysInManifest.sort(),
          ['en', 'en-Dvorak', 'ko', 'number', 'zh-Hans-Pinyin']);
  
        // Verify dictionaries are not built (except en_us.dict)
        dicts.forEach(function(dict) {
          var entry = zip.getEntry(dict);
          assert.equal(entry, null, 'Dictionary should not be built: ' + dict);
        });
  
        // Verify dictionary config
        var dictJSON = JSON.parse(fs.readFileSync(
              appDirPath +
              '/test/build/integration/resources/' +
              'default-make-en-dict-layouts.json'));
  
        checkLayoutsJSON(zipPath, dictJSON);
  
        done();
      });
    });
  });
  
  suite('Keyboard settings building tests', function() {
    suiteSetup(helper.cleanupWorkspace);
    teardown(helper.cleanupWorkspace);
  
    // parse settings.html and return domDoc.
    var getSettingsDomDoc = function() {
      var zipPath = path.join(process.cwd(), 'profile',
        'webapps', 'keyboard.gaiamobile.org', 'application.zip');
  
      // Verify settings.html content in manifest
      var zip = new AdmZip(zipPath);
      var entry = zip.getEntry('settings.html');
      return jsdom(zip.readAsText(entry));
    };
  
    // return an array of <scripts> tag in <head>
    var getScriptsFromDomDoc = function(domDoc) {
      // We don't have Array.from in our node version, so use an old way to
      // convert HTMLCollections to array
      return Array.prototype.slice.call(
               domDoc.head.getElementsByTagName('script'));
    };
  
    suite('For handwriting', function() {
      // return an array of <sections> in the general panel
      var getSectionsFromGeneralPanel = function(domDoc) {
        return Array.prototype.slice.call(
                 domDoc.querySelectorAll('#general-container > section'));
      };
  
      // default: there shouldn't be handwriting elements in resulting file
      test('APP=keyboard make', function(done) {
        var cmd = 'APP=keyboard make';
        helper.exec(cmd, function(error, stdout, stderr) {
          helper.checkError(error, stdout, stderr);
  
          var settingsDOMDoc = getSettingsDomDoc();
  
          assert.isTrue(getScriptsFromDomDoc(settingsDOMDoc).every(function(elem){
            return elem.src !== 'js/settings/handwriting_settings_view.js';
          }), 'No script should include handwriting_settings_view.js');
  
          assert.isTrue(
          getSectionsFromGeneralPanel(settingsDOMDoc).every(function(elem){
            return elem.id !== 'handwriting-settings';
          }), 'No section in general panel should include handwriting settings');
  
          done();
        });
      });
  
      test('GAIA_KEYBOARD_LAYOUTS=zh-Hans-Handwriting APP=keyboard make',
      function(done) {
        var cmd = 'GAIA_KEYBOARD_LAYOUTS=zh-Hans-Handwriting APP=keyboard make';
        helper.exec(cmd, function(error, stdout, stderr) {
          helper.checkError(error, stdout, stderr);
  
          var settingsDOMDoc = getSettingsDomDoc();
  
          assert.isTrue(getScriptsFromDomDoc(settingsDOMDoc).some(function(elem){
            return elem.src === 'js/settings/handwriting_settings_view.js';
          }), 'Some script should include handwriting_settings_view.js');
  
          assert.isTrue(
          getSectionsFromGeneralPanel(settingsDOMDoc).some(function(elem){
            return elem.id === 'handwriting-settings';
          }),
            'Some section in general panel should include handwriting settings');
  
          done();
        });
      });
    });
  });
  