#!/usr/bin/env python3
# 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.

import argparse
import json
import os
import sys
import time

import json5

ALL_BENCHMARKS = (
    '64KB-min.json',
    'bitly-usa-gov.json',
    'twitter.json',
)

DEFAULT_ITERATIONS = 3

THIS_DIR = os.path.abspath(os.path.dirname(__file__))


def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('--pure', action='store_true')
    parser.add_argument(
        '-n', '--num-iterations', default=DEFAULT_ITERATIONS, type=int
    )
    parser.add_argument('benchmarks', nargs='*')
    args = parser.parse_args()
    if not args.benchmarks:
        args.benchmarks = [os.path.join(THIS_DIR, d) for d in ALL_BENCHMARKS]

    file_contents = []
    for f in args.benchmarks:
        with open(f, encoding='utf-8') as fp:
            file_contents.append(fp.read())

    # json.decoder.c_scanstring = py_scanstring
    def py_maker(*args, **kwargs):
        del args
        del kwargs
        decoder = json.JSONDecoder()
        decoder.scan_once = json.scanner.py_make_scanner(decoder)
        decoder.parse_string = json.decoder.py_scanstring
        json.decoder.scanstring = decoder.parse_string
        return decoder

    maker = py_maker if args.pure else json.JSONDecoder

    all_times = []
    for i, c in enumerate(file_contents):
        json_time = 0.0
        json5_time = 0.0
        for _ in range(args.num_iterations):
            start = time.time()
            json_obj = json.loads(c, cls=maker)
            mid = time.time()
            json5_obj = json5.loads(c)
            end = time.time()

            json_time += mid - start
            json5_time += end - mid
            assert json5_obj == json_obj
        all_times.append((json_time, json5_time))

    for i, (json_time, json5_time) in enumerate(all_times):
        fname = os.path.basename(args.benchmarks[i])
        if json5_time and json_time:
            if json5_time > json_time:
                avg = json5_time / json_time
                print(
                    f'{fname:-%20s}: JSON was {avg:5.1f}x faster '
                    f'({json_time:.6f} to {json5_time:.6fs}'
                )
            else:
                avg = json_time / json5_time
                print(
                    f'{fname:-%20s}: JSON5 was {avg:5.1f}x faster '
                    f'({json5_time:.6f} to {json_time:.6fs}'
                )
        elif json5_time:
            print(
                f'{fname:-20s}: JSON5 took {json5_time:.6f} secs, '
                f'JSON was too fast to measure'
            )
        elif json_time:
            print(
                f'{fname:-20s}: JSON took {json_time:.6f} secs, '
                f'JSON5 was too fast to measure'
            )
        else:
            print(f'{fname:-20s}: both were too fast to measure')

    return 0


if __name__ == '__main__':
    sys.exit(main())
