#!/usr/bin/env python3
#
# Copyright 2016 The Fontbakery Authors
# Copyright 2017 The Google Font Tools Authors
#
# 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.
#
from __future__ import print_function

import argparse
import os
import sys
import requests
if int(sys.version[0]) == 2:
    import urlparse
elif int(sys.version[0]) == 3:
    import urllib.parse as urlparse
from gftools.fonts_public_pb2 import FamilyProto
from google.protobuf import text_format

description = ("This script compares the info on local METADATA.pb files"
               " with data fetched from the Google Fonts Developer API.\n\n"
               " In order to use it you need to provide an API key.")
parser = argparse.ArgumentParser(description=description)
parser.add_argument('key', help='Key from Google Fonts Developer API')
parser.add_argument('repo',
                    help=('Directory tree that contains'
                          ' directories with METADATA.pb files.'))
parser.add_argument('--cache',
                    help=('Directory to store a copy'
                          ' of the files in the fonts developer API.'),
                    default="/tmp/gftools-compare-git-api")
parser.add_argument('--verbose',
                    help='Print additional information',
                    action="store_true")
parser.add_argument('--ignore-copy-existing-ttf', action="store_true")
parser.add_argument('--autofix',
                    help='Apply automatic fixes to files.',
                    action="store_true")
parser.add_argument('--api',
                    help='Domain string to use to request.',
                    default="fonts.googleapis.com")


def get_cache_font_path(cache_dir, fonturl):
    urlparts = urlparse.urlparse(fonturl)
    cache_dir = os.path.join(cache_dir,
                             urlparts.netloc,
                             os.path.dirname(urlparts.path).strip('/'))
    if not os.path.exists(cache_dir):
        os.makedirs(cache_dir)
    fontname = os.path.basename(fonturl)
    return os.path.join(cache_dir, fontname)

def getVariantName(item):
    if item.style == "normal" and item.weight == 400:
        return "regular"

    name = ""
    if item.weight != 400:
        name = str(item.weight)

    if item.style != "normal":
        name += item.style

    return name


API_URL = 'https://www.googleapis.com/webfonts/v1/webfonts?key={}'
def main(args=None):
    args = parser.parse_args(args)
    response = requests.get(API_URL.format(args.key))
    try:
        webfontList = response.json()['items']
        webfontListFamilyNames = [item['family'] for item in webfontList]
    except (ValueError, KeyError):
        sys.exit("Unable to load and parse"
                 " list of families from Google Web Fonts API.")

    for dirpath, dirnames, filenames in os.walk(args.repo):
        metadata_path = os.path.join(dirpath, 'METADATA.pb')
        if not os.path.exists(metadata_path):
            continue

        metadata = FamilyProto()
        text_data = open(metadata_path, "rb").read()
        text_format.Merge(text_data, metadata)
        try:
            family = metadata.name
        except KeyError:
            print(('ERROR: "{}" does not contain'
                   ' familyname info.').format(metadata_path),
                  file=sys.stderr)
            continue

        try:
            index = webfontListFamilyNames.index(family)
            webfontsItem = webfontList[index]
        except ValueError:
            print(('ERROR: Family "{}" could not be found'
                   ' in Google Web Fonts API.').format(family))
            continue

        webfontVariants = []
        log_messages = []
        for variant, fonturl in webfontsItem['files'].items():
            cache_font_path = get_cache_font_path(args.cache, fonturl)
            webfontVariants.append(variant)

            if args.ignore_copy_existing_ttf and os.path.exists(cache_font_path):
                continue

            with open(cache_font_path, 'w') as fp:
                found = False
                for font in metadata.fonts:
                    if getVariantName(font) == variant:
                        found = True
                        if args.verbose:
                            print('Downloading "{}"'
                                  ' as "{}"'.format(fonturl,
                                                    font.filename))

                        #Saving:
                        fp.write(requests.get(fonturl).text)

                        #Symlinking:
                        src = cache_font_path
                        dst_dir = os.path.dirname(cache_font_path)
                        dst = os.path.join(dst_dir, font.filename)
                        if not os.path.exists(dst):
                            os.symlink(src, dst)
                if not found:
                    print(("ERROR: Google Fonts API references"
                           " a '{}' variant which is not declared"
                           " on local '{}'.").format(variant,
                                                     metadata_path))

        for subset in webfontsItem['subsets']:
            if subset == "menu":
                # note about Google Web Fonts:
                # Menu subsets are no longer generated offline.
                continue

            if subset not in metadata.subsets:
                print(('ERROR: "{}" '
                       'lacks subset "{}" in git.').format(family, subset),
                      file=sys.stderr)
            else:
                if args.verbose:
                    print(('OK: "{}" '
                           'subset "{}" in sync.').format(family, subset))

        for subset in metadata.subsets:
            if subset != "menu" and subset not in webfontsItem['subsets']:
                print(('ERROR: "{}" '
                       'lacks subset "{}" in API.').format(family, subset),
                      file=sys.stderr)

        if metadata.category == "SANS_SERIF":  # That's fine :-)
            category = "sans-serif"
        else:
            category = metadata.category.lower()

        if category != webfontsItem['category']:
            print(('ERROR: "{}" category "{}" in git'
                   ' does not match category "{}"'
                   ' in API.').format(family,
                                      metadata.category,
                                      webfontsItem['category']))
        else:
            if args.verbose:
                print(('OK: "{}" '
                       'category "{}" in sync.').format(family,
                                                        metadata.category))


        for variant in webfontVariants:
            try:
                idx = [getVariantName(f) for f in metadata.fonts].index(variant)
                repoFileName = metadata.fonts[idx].filename

                fonturl = webfontsItem['files'][variant]
                fontpath = get_cache_font_path(args.cache, fonturl)

                import hashlib
                google_md5 = hashlib.md5(open(fontpath, 'rb').read()).hexdigest()
                data = open(os.path.join(dirpath, repoFileName), 'rb').read()
                repo_md5 = hashlib.md5(data).hexdigest()

                if repo_md5 == google_md5:
                    log_messages.append([variant,
                                         'OK',
                                         '"{}" in sync'.format(repoFileName)])
                else:
                    log_messages.append([variant,
                                         'ERROR',
                                         ('"{}" checksum mismatch, file'
                                          ' in API does not match file'
                                          ' in git.').format(repoFileName)])

            except ValueError:
                log_messages.append([variant,
                                     'ERROR',
                                     ('"{}" available in API but'
                                      ' not in git.').format(font.filename)])

        for font in metadata.fonts:
            variant = getVariantName(font)
            try:
                webfontVariants.index(variant)
            except ValueError:
                log_messages.append([variant,
                                     'ERROR',
                                     ('"{}" available in git but'
                                      ' not in API.').format(font.filename)])

        # Sort all the messages by their respective
        # metadataFileName and print them:
        for message in sorted(log_messages, key=lambda x: x[0].lower()):
            variant, status, text = message
            if status == "OK":
                if args.verbose:
                    print('{}: {}'.format(status, text))
            else:
                print('{}: {}'.format(status, text), file=sys.stderr)

if __name__ == '__main__':
  main()

