#!/usr/bin/env python3
# Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file
# for details. All rights reserved. Use of this source code is governed by a
# BSD-style license that can be found in the LICENSE file.

import database
import databasebuilder
import idlnode
import logging.config
import os.path
import sys
import time
import utilities
import dependency
from idlnode import IDLType, resolveTypedef

_logger = logging.getLogger('fremontcutbuilder')

# See:
#  http://src.chromium.org/viewvc/multivm/trunk/webkit/Source/core/features.gypi
# for ENABLE_* flags defined in Chromium / Blink.
# We list all ENABLE flags used in IDL in one of these two lists.
FEATURE_DISABLED = [
    'ENABLE_CUSTOM_SCHEME_HANDLER',
    'ENABLE_MEDIA_CAPTURE',  # Only enabled on Android.
    'ENABLE_ORIENTATION_EVENTS',  # Only enabled on Android.
    'ENABLE_WEBVTT_REGIONS',
]

FEATURE_DEFINES = [
    'ENABLE_CALENDAR_PICKER',  # Not on Android
    'ENABLE_ENCRYPTED_MEDIA_V2',
    'ENABLE_INPUT_SPEECH',  # Not on Android
    'ENABLE_LEGACY_NOTIFICATIONS',  # Not on Android
    'ENABLE_NAVIGATOR_CONTENT_UTILS',  # Not on Android
    'ENABLE_NOTIFICATIONS',  # Not on Android
    'ENABLE_SVG_FONTS',
    'ENABLE_WEB_AUDIO',  # Not on Android
]


# Resolve all typedefs encountered while parsing (see idlnode.py), resolve any typedefs not resolved
# during parsing.  This must be done before the database is created, merged, and augmented to
# exact type matching.  Typedefs can be encountered in any IDL and usage can cross IDL boundaries.
def ResolveAllTypedefs(all_interfaces):
    # Resolve all typedefs.
    for interface, db_Opts in all_interfaces:

        def IsIdentified(idl_node):
            node_name = idl_node.id if idl_node.id else 'parent'
            for idl_type in idl_node.all(idlnode.IDLType):
                # One last check is the type a typedef in an IDL file (the typedefs
                # are treated as global).
                resolvedType = resolveTypedef(idl_type)
                if (resolvedType != idl_type):
                    idl_type.id = resolvedType.id
                    idl_type.nullable = resolvedType.nullable
                    continue
            return True

        interface.constants = filter(IsIdentified, interface.constants)
        interface.attributes = filter(IsIdentified, interface.attributes)
        interface.operations = filter(IsIdentified, interface.operations)
        interface.parents = filter(IsIdentified, interface.parents)


def build_database(idl_files,
                   database_dir,
                   feature_defines=None,
                   logging_level=logging.WARNING,
                   examine_idls=False):
    """This code reconstructs the FremontCut IDL database from W3C,
  WebKit and Dart IDL files."""
    current_dir = os.path.dirname(__file__)
    logging.config.fileConfig(os.path.join(current_dir, "logging.conf"))

    _logger.setLevel(logging_level)

    db = database.Database(database_dir)

    # Delete all existing IDLs in the DB.
    db.Delete()

    builder = databasebuilder.DatabaseBuilder(db)
    dependency.set_builder(builder)

    # TODO(vsm): Move this to a README.
    # This is the Chrome revision.
    webkit_revision = '63'

    # TODO(vsm): Reconcile what is exposed here and inside WebKit code
    # generation.  We need to recheck this periodically for now.
    webkit_defines = ['LANGUAGE_DART', 'LANGUAGE_JAVASCRIPT']

    if feature_defines is None:
        feature_defines = FEATURE_DEFINES

    webkit_options = databasebuilder.DatabaseBuilderOptions(
        # TODO(vsm): What else should we define as on when processing IDL?
        idl_defines=webkit_defines + feature_defines,
        source='WebKit',
        source_attributes={'revision': webkit_revision},
        logging_level=logging_level)

    # Import WebKit IDLs.
    builder.import_idl_files(idl_files, webkit_options, False)

    # Import Dart idl:
    dart_options = databasebuilder.DatabaseBuilderOptions(
        source='Dart',
        rename_operation_arguments_on_merge=True,
        logging_level=logging_level)

    utilities.KNOWN_COMPONENTS = frozenset(['core', 'modules', 'dart'])

    builder.import_idl_files(
        [os.path.join(current_dir, '..', 'idl', 'dart', 'dart.idl')],
        dart_options, True)

    start_time = time.time()

    # All typedefs MUST be resolved here before any database fixups (merging, implements, etc.)
    ResolveAllTypedefs(builder._imported_interfaces)

    # Merging:
    builder.merge_imported_interfaces()

    builder.fetch_constructor_data(webkit_options)
    builder.fix_displacements('WebKit')

    # Cleanup:
    builder.normalize_annotations(['WebKit', 'Dart'])

    # Map any IDL defined dictionaries to Dictionary.
    builder.map_dictionaries()

    # Examine all IDL and produce a diagnoses of areas (e.g., list dictionaries
    # declared and usage, etc.)
    if examine_idls:
        builder.examine_database()

    conditionals_met = set(
        'ENABLE_' + conditional for conditional in builder.conditionals_met)
    known_conditionals = set(FEATURE_DEFINES + FEATURE_DISABLED)

    unused_conditionals = known_conditionals - conditionals_met
    if unused_conditionals:
        _logger.warning('There are some unused conditionals %s' %
                        sorted(unused_conditionals))
        _logger.warning('Please update fremontcutbuilder.py')

    unknown_conditionals = conditionals_met - known_conditionals
    if unknown_conditionals:
        _logger.warning('There are some unknown conditionals %s' %
                        sorted(unknown_conditionals))
        _logger.warning('Please update fremontcutbuilder.py')

    print('Merging interfaces %s seconds' % round(time.time() - start_time, 2))

    return db


def main(parallel=False, logging_level=logging.WARNING, examine_idls=False):
    current_dir = os.path.dirname(__file__)

    idl_files = []

    # Check default location in a regular dart enlistment.
    webcore_dir = os.path.join(current_dir, '..', '..', '..', 'third_party',
                               'WebCore')

    if not os.path.exists(webcore_dir):
        # Check default location in a dartium enlistment.
        webcore_dir = os.path.join(current_dir, '..', '..', '..', '..',
                                   'third_party', 'WebKit', 'Source')

    if not os.path.exists(webcore_dir):
        raise RuntimeError('directory not found: %s' % webcore_dir)

    DIRS_TO_IGNORE = [
        'bindings',  # Various test IDLs
        'testing',  # IDLs to expose testing APIs
        'networkinfo',  # Not yet used in Blink yet
        'vibration',  # Not yet used in Blink yet
        'inspector',
    ]

    # TODO(terry): Integrate this into the htmlrenamer's _removed_html_interfaces
    #              (if possible).
    FILES_TO_IGNORE = [
        'InspectorFrontendHostFileSystem.idl',  # Uses interfaces in inspector dir (which is ignored)
        'WebKitGamepad.idl',  # Gamepad.idl is the new one.
        'WebKitGamepadList.idl',  # GamepadList is the new one.
    ]

    def visitor(arg, dir_name, names):
        if os.path.basename(dir_name) in DIRS_TO_IGNORE:
            names[:] = []  # Do not go underneath
        for name in names:
            file_name = os.path.join(dir_name, name)
            (interface, ext) = os.path.splitext(file_name)
            if ext == '.idl' and not (name in FILES_TO_IGNORE):
                idl_files.append(file_name)

    os.path.walk(webcore_dir, visitor, webcore_dir)

    database_dir = os.path.join(current_dir, '..', 'database')

    return build_database(
        idl_files,
        database_dir,
        logging_level=logging_level,
        examine_idls=examine_idls)


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