#!/usr/bin/env python
#
# Copyright 2017 Google Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Generate html page with waterfalls for a number of fonts."""

import argparse
import codecs
import os
from os import path
import re
import shutil

from nototools import lang_data
from nototools import noto_fonts
from nototools import tool_utils

def _add_styles(lines, prefix, font_names, font_sizes):
  lines.append(prefix + '<style>')

  for i, font_name in enumerate(font_names):
    lines.append(prefix + '  @font-face {')
    lines.append(
        prefix + '    font-family: "font_%d"; src: url("fonts/%s");' % (
            i, font_name))
    lines.append(prefix + '  }')
  lines.append('')

  for i in range(len(font_names)):
    lines.append(prefix + '  .f%d { font-family: "font_%d" }' % (i, i))
  lines.append('')

  for i, s in enumerate(font_sizes):
    lines.append(prefix + '  .s%d { font-size: %dpx }' % (i, s))
  lines.append('')

  lines.append(prefix + '  th { font-size: 14px }')
  lines.append(prefix + '  td { white-space: nowrap }')

  lines.append(prefix + '</style>')


_JS_LINES = """
<script>
  function _font_select(target) {
    var index = target.value.substring(1)
    _show_div(index)
  }

  function _show_div(index) {
    var div_name = "div_" + index
    var divs = document.getElementsByTagName("div")
    for (var i = 0; i < divs.length; i++) {
      var div = divs[i]
      if (div.id.startsWith("div_")) {
        var display = div.id == div_name ? "block" : "none"
        div.style.display = display
      }
    }
  }
</script>"""

def _add_js(lines, prefix):
  for line in _JS_LINES.splitlines():
    line = line.rstrip()
    if line:
      lines.append(prefix + line)
    else:
      lines.append('')


def _add_example(lines, prefix, index, name, sizes, text):
  lines.append(prefix + '<div id="div_%d">' % index)
  lines.append(prefix + '  <h3>%s</h3>' % name)
  lines.append(prefix + '  <table>')
  for i, s in enumerate(sizes):
    lines.append(prefix + '    <tr><th>%dpx:<td class="f%d s%d">%s' % (
        s, index, i, text))
  lines.append(prefix + '  </table>')
  lines.append(prefix + '</div>')


def _add_examples(lines, prefix, font_names, font_sizes, text):
  for i, name in enumerate(font_names):
    _add_example(lines, prefix, i, name, font_sizes, text)


def _add_example_switch(lines, prefix, font_names):
  lines.append(prefix + '<p>Select font')
  lines.append(prefix + '<select name="font_select" '
               'onchange="_font_select(this)">')
  for i, name in enumerate(font_names):
    lines.append(prefix + '  <option value="f%d">%s</option>' % (i, name))
  lines.append(prefix + '</select>')


def _write_html(directory, font_names, font_sizes, text, out_file):
  lines = [
      '<html lang="en">',
      '  <head>',
      '    <meta charset="utf-8">',
      '    <title>Font specimens</title>']
  _add_styles(lines, '    ', font_names, font_sizes)
  _add_js(lines, '    ')
  lines.append('  </head>')

  lines.append('  <body onload="_show_div(0)">')
  _add_example_switch(lines, '    ', font_names)
  _add_examples(lines, '    ', font_names, font_sizes, text)
  lines.append('  </body>')

  lines.append('</html>')
  lines.append('')

  html_text = '\n'.join(lines)
  if out_file:
    with codecs.open(out_file, 'w', 'utf-8') as f:
      f.write(html_text)
    print('wrote %s' % out_file)
  else:
    print(html_text)


def _get_font_list(root, name_str):
  match_re = re.compile(r'.*%s.*\.(?:ttf|otf)$' % name_str)
  font_list = []
  for d in [root, path.join(root, 'hinted'), path.join(root, 'unhinted')]:
    if path.isdir(d):
      font_list.extend(
          path.join(d, f)[len(root)+1:] for f in os.listdir(d)
          if match_re.match(f))
  return sorted(font_list)


def _get_sample_text(directory, font_names, lang):
  script_keys = set()
  scripts = set()
  for name in font_names:
    noto_font = noto_fonts.get_noto_font(path.join(directory, name))
    if noto_font.script not in script_keys:
      script_keys.add(noto_font.script)
      scripts |= noto_fonts.script_key_to_scripts(noto_font.script)

  if lang:
    lang_scripts = ['%s-%s' % (lang, script) for script in scripts]
  else:
    lang_scripts = [
        '%s-%s' % (lang_data.script_to_default_lang(script), script)
        for script in scripts]
  lang_scripts.extend('und-%s' % script for script in scripts)

  samples = []
  sample_dir = tool_utils.resolve_path('[tools]/sample_texts')
  for f in os.listdir(sample_dir):
    for lang_script in lang_scripts:
      if f.startswith(lang_script):
        samples.append(f)
        break

  print(sorted(samples))
  # limit to scripts supported by all fonts
  selected = []
  for sample in samples:
    sample_supported=True
    for script_key in script_keys:
      script_key_supported = False
      for script in noto_fonts.script_key_to_scripts(script_key):
        if '-%s_' % script in sample:
          script_key_supported = True
          break
      if not script_key_supported:
        sample_supported = False
        break
    if sample_supported:
      selected.append(sample)
  if not selected:
    raise Exception('no sample supported by all fonts')
  samples = selected

  # limit to udhr ones if any exist
  selected = [s for s in samples if '_udhr' in s]
  if selected:
    samples = selected
  # limit to non-'und' ones if any exist
  selected = [s for s in samples if not s.startswith('und-')]
  if selected:
    samples = selected
  if len(samples) != 1:
    raise Exception (
        'found %d sample files (%s) but need exactly 1' % (
            len(samples), ', '.join(sorted(samples))))
  print('selected sample %s' % samples[0])

  with codecs.open(path.join(sample_dir, samples[0]), 'r', 'utf-8') as f:
    text = f.read()
  return text.strip()


def generate(root, font_str, font_sizes, text, lang, out_file):
  root = tool_utils.resolve_path(root)
  if not path.isdir(root):
    raise Exception('%s is not a directory' % root)

  font_names = _get_font_list(root, font_str)
  if not font_names:
    raise Exception('no fonts matching "%s" in %s' % (font_str, root))

  print('found %d fonts under %s:\n  %s' % (
      len(font_names), root, '\n  '.join(sorted(font_names))))

  if not font_sizes:
    font_sizes = [10, 11, 12, 13, 14, 15, 16, 17, 18, 20, 22, 24, 28, 32]

  if not text:
    text = _get_sample_text(root, font_names, lang)

  if out_file:
    out_file = path.abspath(out_file)
    file_dir = tool_utils.ensure_dir_exists(path.dirname(out_file))
    if path.exists(out_file):
      print('file %s already exists, overwriting' % out_file)
    font_dir = tool_utils.ensure_dir_exists(path.join(file_dir, 'fonts'))
    for font_name in font_names:
      src = path.join(root, font_name)
      dst = tool_utils.ensure_dir_exists(
          path.dirname(path.join(font_dir, font_name)))
      shutil.copy2(src, dst)

  _write_html(root, font_names, font_sizes, text, out_file)


def main():
  parser = argparse.ArgumentParser()
  parser.add_argument(
      '-r', '--root', help='directory containing fonts, optionally in '
      'hinted/unhinted subdirs', default='[fonts]', required=True,
      metavar='dir')
  parser.add_argument(
      '-n', '--name_str', help='string to match font name', required=True,
      metavar='str')
  parser.add_argument(
      '-t', '--text', help='text to use, defaults to udhr text for the '
      'script when there is a common script', metavar='str')
  parser.add_argument(
      '-l', '--lang', help='language string to select among multiple texts '
      'for a script', metavar='lang')
  parser.add_argument(
      '-o', '--out_file', help='name of file to output', nargs='?',
      const='specimens.html', metavar='file')
  parser.add_argument(
      '-s', '--sizes', help='font sizes', nargs='+', type=int,
      metavar='size')
  args = parser.parse_args()
  generate(
      args.root, args.name_str, args.sizes, args.text, args.lang, args.out_file)


if __name__ == '__main__':
  main()
