#!/usr/bin/env python
#
# Copyright 2015 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.

"""Interactively generate sample text for a font.

Often in bug reports people will describe text using character names.
Replicating the sample text they describe can be a bit tedious.  This
lets you interactively search characters in the font by name to assemble
a string and save it to a file."""

from builtins import input
import argparse
import codecs

from nototools.py23 import unichr
from nototools import coverage
from nototools import unicode_data


def _help():
  print ('enter a string to match or one of the following:\n'
         '  \'quit\' to exit,\n'
         '  \'help\' to show these options,\n'
         '  \'names\' for names,\n'
         '  \'dump\' to dump the current text,\n'
         '  \'clear\' to clear the current text,\n'
         '  \'write\' to be prompted for a filename to write the text to.')


def _build_text(name_map, initial_text=''):
  text = initial_text
  print('build text using map of length %d' % len(name_map))
  while True:
    line = input('> ')
    if not line:
      continue
    if line == 'quit':
      break
    if line == 'help':
      _help()
      continue
    if line == 'names':
      print('names:\n  ' + '\n  '.join(sorted(name_map.keys())))
      continue
    if line == 'dump':
      print('dump: \'%s\'' % text)
      for cp in text:
        print('%06x %s' % (ord(cp), unicode_data.name(ord(cp))))
      continue
    if line == 'clear':
      text = ''
      continue
    if line == 'write':
      line = input('file name> ')
      if line:
        _write_text(line, text)
      continue

    matches = []
    for name, cp in sorted(name_map.items()):
      if line in name:
        matches.append(name)
    if not matches:
      print('no match for "%s"'% line)
      continue

    if len(matches) == 1:
      print(matches[0])
      text += unichr(name_map[matches[0]])
      continue

    # if we match a full line, then use that
    if line in matches:
      print(line)
      text += unichr(name_map[line])
      continue

    new_matches = []
    for m in matches:
      if line in m.split(' '):
        new_matches.append(m)

    # if we match a full word, and only one line has this full word, use that
    if len(new_matches) == 1:
      print(new_matches[0])
      text += unichr(name_map[new_matches[0]])
      continue

    select_multiple = True
    while select_multiple:
      print('multiple matches:\n  ' + '\n  '.join(
          '[%2d] %s' % (i, n) for i, n in enumerate(matches)))
      while True:
        line = input('0-%d or q to skip> ' % (len(matches) - 1))
        if line == 'q':
          select_multiple = False
          break
        try:
          n = int(line)
          break
        except ValueError:
          continue

      if not select_multiple: # q
        break

      if n < 0 or n >= len(matches):
        print('%d out of range' % n)
        continue

      text += unichr(name_map[matches[n]])
      select_multiple = False

  print('done.')
  return text


def _get_char_names(charset):
  name_map = {}
  if charset:
    for cp in charset:
      try:
        name = unicode_data.name(cp)
      except:
        name = None
      if not name or name == '<control>':
        name = '%04x' % cp
      else:
        name = '%04x %s' % (cp, name.lower())
      name_map[name] = cp

  return name_map


def _write_text(filename, text):
  with codecs.open(filename, 'w', 'utf-8') as f:
    f.write(text)
  print('wrote %s' % filename)


def main():
  parser = argparse.ArgumentParser()
  parser.add_argument(
      '-f', '--font',
      help='font whose character map to restrict text to',
      required=True)
  parser.add_argument(
      '-t', '--text',
      help='initial text, prepend @ to read from file')

  args = parser.parse_args()
  if args.text:
    if args.text[0] == '@':
      with codecs.open(args.text[1:], 'r', 'utf-8') as f:
        text = f.read()
    else:
      text = args.text
  else:
    text = ''

  if args.font:
    charset = coverage.character_set(args.font)
    name_map = _get_char_names(charset)
    text = _build_text(name_map, text)
    print('text: ' + text)
  else:
    charset = None


if __name__ == '__main__':
    main()
