// =============================================================================
// Auto-translate Courses using Google Translate
// (c) Mathigon
// =============================================================================


/* const fs = require('fs');
const path = require('path');
const marked = require('marked');
const JSDom = require('jsdom').JSDOM;
const yaml = require('js-yaml');
const {Translate} = require('@google-cloud/translate').v2;


// -----------------------------------------------------------------------------
// Markdown Extensions

let STORE = [];
let originalP = undefined;  // Caching of unparsed paragraphs (for blockquotes)

function storeToken(string) {
  STORE.push(string);
  return `<img sx="${STORE.length - 1}"/>`;
}

function storeTag(start, text, end) {
  STORE.push(start, end);
  return `<span sx="${STORE.length - 2}">${text}</span>`;
}

function parseParagraph(text) {
  originalP = text;
  return text.replace(/\s+/g, ' ')
      .replace(/\[\[([^\]]+)]]/g, (x, body) => storeTag('[[', body.split('|').join(storeToken('|')), ']]'))
      .replace(/\${([^}]+)}{([^}]+)}/g, storeToken)
      .replace(/\${([^}]+)}(?!<\/x-var>)/g, storeToken)
      .replace(/:\w+:/, storeToken);
}

const renderer = new marked.Renderer();
renderer.link = (href, title, text) => storeTag('[', text, `](${href})`);
renderer.heading = (text, level) => storeToken('#'.repeat(level)) + ' ' + text + '\n\n';
renderer.codespan = (code) => storeToken('`' + code + '`');
renderer.blockquote = () => storeToken(originalP.split('\n').map(x => '> ' + x).join('\n')) + '\n\n';
renderer.hr = () => storeToken('---') + '\n\n';
renderer.code = (code) => storeToken(code.split('\n').map(x => '    ' + x).join('\n')) + '\n\n';
renderer.list = (text) => text + '\n\n';
renderer.listitem = (text) => '* ' + parseParagraph(text) + '\n';
renderer.paragraph = (text) => parseParagraph(text) + '\n\n';
renderer.strong = (text) => storeTag('__', text, '__');
renderer.em = (text) => storeTag('_', text, '_');

// -----------------------------------------------------------------------------

function encode(content) {
  STORE = [];

  // Block Indentation
  content = content.split('\n').map((line) => {
    if (!line.startsWith(':::')) return line;
    return '\n\n' + storeToken(line) + '\n\n';
  }).join('\n');

  // Parse Markdown (but override HTML detection)
  const lexer = new marked.Lexer();
  lexer.tokenizer.rules.block.html = /^<.*[\n]{2,}/;
  const tokens = lexer.lex(content);
  let parsed = marked.Parser.parse(tokens, {renderer});

  // Parse custom element attributes and whitespace
  parsed = parsed.replace(/{([^}]+)}/g, storeToken).replace(/&nbsp;/g, ' ');

  // Split into sections of length at most 5000.
  const output = [''];
  for (const row of parsed.split(/\n\n+/)) {
    if (output[output.length - 1].length + row.length < 4950) {
      output[output.length - 1] += '<p sx>' + row + '</p>';
    } else {
      output.push('<p sx>' + row + '</p>');
    }
  }

  return [output, STORE];
}

// -----------------------------------------------------------------------------

function toString(element, STORE) {
  if (element.nodeName === '#text') return element.textContent;

  const body = Array.from(element.childNodes).map(c => toString(c, STORE)).join('');
  const key = +element.getAttribute('sx');

  if (element.matches('img[sx]')) return STORE[key];
  if (element.matches('span[sx]')) return STORE[key] + body.trim() + STORE[key + 1];
  if (element.matches('p[sx]')) return body;

  const clone = element.cloneNode();
  clone.innerHTML = '?x?';
  return clone.outerHTML.replace('?x?', body.trim());
}

function decode(text, STORE) {
  const body = (new JSDom(text)).window.document.body;
  let output = Array.from(body.querySelectorAll('p[sx]'))
      .map(p => toString(p, STORE)).join('\n\n');

  // Clean up syntax and special characters
  output = output.replace(/\n\n+/g, '\n\n').replace(/---\n\n>/g, '---\n>')
      .replace(/&quot;/g, '"').replace(/&gt;/g, '>').replace(/&lt;/g, '<')
      .replace(/'/g, '\'').replace(/\s°/g, '°').replace(/\s*<br>\s* /g, '  \n')
      .trim() + '\n';

  // Remove comments
  output = output.split('\n').filter(s => !s.startsWith('    //')).join('\n');

  // Remove leading whitespace
  output = output.split('\n\n').map(s => (s.startsWith(' ') && !s.startsWith('    ')) ? s.slice(1) : s)
      .join('\n\n').replace(/\n\n+/g, '\n\n');

  // TODO Fix tables and lists

  return output;
}


async function loadFromGoogle(string, lang) {
  const id = lang.replace('cn', 'zh-CN');  // Special language codes...
  const result = await Google.translate(string, id);
  return Array.isArray(result) ? result[0] : result;
}

async function translate(string, lang) {
  if (!string) return '';
  const [str, store] = encode(string);
  return decode(await loadFromGoogle(str[0], lang), store).trim();
}

// -----------------------------------------------------------------------------

async function shared(type, lang, fields) {
  const enFile = fs.readFileSync(INPUT + `shared/${type}.yaml`, 'utf8');
  const en = yaml.safeLoad(enFile);
  const intro = enFile.split('\n').slice(0, 5).join('\n');

  const file = OUTPUT + `${lang}/shared/${type}.yaml`;
  const source = (fs.existsSync(file) ? fs.readFileSync(file, 'utf8') : '')
      .replace(/: \|/g, ': >');  // Fix newline characters

  const output = {};
  const local = yaml.safeLoad(source) || {};

  for (const key of Object.keys(en)) {
    output[key] = Object.assign({}, local[key] || en[key]);
    if (key in local) continue;

    if (fields) {
      // Specific fields for bios and glossary
      for (const f of fields) output[key][f] = await translate(en[key][f], lang);
    } else if (Array.isArray(en[key])) {
      // Hints with arrays
      output[key] = await Promise.all(en[key].map(k => translate(k, lang)));
    } else {
      // Hints without arrays
      output[key] = await translate(en[key], lang);
    }
  }

  // TODO Fix newlines between lists and bullets in Markdown.
  const result = yaml.safeDump(output, {lineWidth: 100})
      .replace(/: [|>]-?/g, ': |')  // Fix newline characters
      .replace(/\n\n+/g, '\n\n')
      .replace(/\n(\w)/g, '\n\n$1');
  fs.writeFileSync(file, intro + result);
}

// -----------------------------------------------------------------------------

async function run() {
  const INPUT = path.join(__dirname, '../content');
  const OUTPUT = path.join(__dirname, '../translations');
  const Google = new Translate({keyFilename: path.join(__dirname, KEY)});

  for (const c of COURSES) {
    const source = fs.readFileSync(`${INPUT}/${c}/content.md`, 'utf8');
    const [items, store] = encode(source);

    for (const l of LANGUAGES) {
      if (fs.existsSync(`${OUTPUT}/${l}/${c}/content.md`)) continue;
      console.log(`>> Generating ${l} translations for ${c}...`);

      let translated = '';
      for (const i of items) translated += (await loadFromGoogle(i, l));

      const output = decode(translated, store);
      fs.writeFileSync(`${OUTPUT}/${l}/${c}/content.md`, output);
    }
  }

  for (const l of LANGUAGES) {
    console.log(`>> Generating ${l} translations for shared files...`);
    // await shared('bios', l, ['bio']);
    // await shared('glossary', l, ['text', 'title']);
    // await shared('hints', l);
  }
} */
