// Copyright (c) 2016, 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.

library fasta.library_builder;

import 'package:kernel/ast.dart' show Library, Nullability;

import '../combinator.dart' show Combinator;

import '../problems.dart' show internalProblem, unsupported;

import '../export.dart' show Export;

import '../loader.dart' show Loader;

import '../messages.dart'
    show
        FormattedMessage,
        LocatedMessage,
        Message,
        templateInternalProblemConstructorNotFound,
        templateInternalProblemNotFoundIn,
        templateInternalProblemPrivateConstructorAccess;

import '../severity.dart' show Severity;

import 'builder.dart'
    show
        ClassBuilder,
        Builder,
        FieldBuilder,
        MemberBuilder,
        ModifierBuilder,
        NameIterator,
        NullabilityBuilder,
        PrefixBuilder,
        Scope,
        ScopeBuilder,
        TypeBuilder;

import 'declaration.dart';

import 'modifier_builder.dart';

abstract class LibraryBuilder implements ModifierBuilder {
  Scope get scope;

  Scope get exportScope;

  ScopeBuilder get scopeBuilder;

  ScopeBuilder get exportScopeBuilder;

  List<Export> get exporters;

  LibraryBuilder partOfLibrary;

  bool mayImplementRestrictedTypes;

  // Deliberately unrelated return type to statically detect more accidental
  // use until Builder.target is fully retired.
  @override
  UnrelatedTarget get target;

  /// Set the langauge version to a specific non-null major and minor version.
  ///
  /// If the language version has previously been explicitly set set (i.e. with
  /// [explicit] set to true), any subsequent call (explicit or not) should be
  /// ignored.
  /// Multiple calls with [explicit] set to false should be allowed though.
  ///
  /// The main idea is that the .packages file specifies a default language
  /// version, but that the library can have source code that specifies another
  /// one which should be supported, but specifying several in code should not
  /// change anything.
  ///
  /// [offset] and [length] refers to the offset and length of the source code
  /// specifying the language version.
  void setLanguageVersion(int major, int minor,
      {int offset: 0, int length, bool explicit});

  bool get isPart;

  Loader get loader;

  /// Returns the [Library] built by this builder.
  Library get library;

  /// Returns the import uri for the library.
  ///
  /// This is the canonical uri for the library, for instance 'dart:core'.
  Uri get uri;

  Iterator<Builder> get iterator;

  NameIterator get nameIterator;

  Builder addBuilder(String name, Builder declaration, int charOffset);

  void addExporter(
      LibraryBuilder exporter, List<Combinator> combinators, int charOffset);

  /// Add a problem with a severity determined by the severity of the message.
  ///
  /// If [fileUri] is null, it defaults to `this.fileUri`.
  ///
  /// See `Loader.addMessage` for an explanation of the
  /// arguments passed to this method.
  FormattedMessage addProblem(
      Message message, int charOffset, int length, Uri fileUri,
      {bool wasHandled: false,
      List<LocatedMessage> context,
      Severity severity,
      bool problemOnLibrary: false});

  /// Returns true if the export scope was modified.
  bool addToExportScope(String name, Builder member, [int charOffset = -1]);

  void addToScope(String name, Builder member, int charOffset, bool isImport);

  Builder computeAmbiguousDeclaration(
      String name, Builder declaration, Builder other, int charOffset,
      {bool isExport: false, bool isImport: false});

  int finishDeferredLoadTearoffs();

  int finishForwarders();

  int finishNativeMethods();

  int finishPatchMethods();

  /// Looks up [constructorName] in the class named [className].
  ///
  /// The class is looked up in this library's export scope unless
  /// [bypassLibraryPrivacy] is true, in which case it is looked up in the
  /// library scope of this library.
  ///
  /// It is an error if no such class is found, or if the class doesn't have a
  /// matching constructor (or factory).
  ///
  /// If [constructorName] is null or the empty string, it's assumed to be an
  /// unnamed constructor. it's an error if [constructorName] starts with
  /// `"_"`, and [bypassLibraryPrivacy] is false.
  MemberBuilder getConstructor(String className,
      {String constructorName, bool bypassLibraryPrivacy: false});

  int finishTypeVariables(ClassBuilder object, TypeBuilder dynamicType);

  /// This method instantiates type parameters to their bounds in some cases
  /// where they were omitted by the programmer and not provided by the type
  /// inference.  The method returns the number of distinct type variables
  /// that were instantiated in this library.
  int computeDefaultTypes(TypeBuilder dynamicType, TypeBuilder bottomType,
      ClassBuilder objectClass);

  void becomeCoreLibrary();

  void addSyntheticDeclarationOfDynamic();

  /// Lookups the member [name] declared in this library.
  ///
  /// If [required] is `true` and no member is found an internal problem is
  /// reported.
  Builder lookupLocalMember(String name, {bool required: false});

  Builder lookup(String name, int charOffset, Uri fileUri);

  /// If this is a patch library, apply its patches to [origin].
  void applyPatches();

  void recordAccess(int charOffset, int length, Uri fileUri);

  void buildOutlineExpressions();

  List<FieldBuilder> takeImplicitlyTypedFields();

  bool get isNonNullableByDefault;

  Nullability get nullable;

  Nullability get nonNullable;

  Nullability nullableIfTrue(bool isNullable);

  NullabilityBuilder get nullableBuilder;

  NullabilityBuilder get nonNullableBuilder;

  NullabilityBuilder nullableBuilderIfTrue(bool isNullable);
}

abstract class LibraryBuilderImpl extends ModifierBuilderImpl
    implements LibraryBuilder {
  @override
  final Scope scope;

  @override
  final Scope exportScope;

  @override
  final ScopeBuilder scopeBuilder;

  @override
  final ScopeBuilder exportScopeBuilder;

  @override
  final List<Export> exporters = <Export>[];

  @override
  LibraryBuilder partOfLibrary;

  @override
  bool mayImplementRestrictedTypes = false;

  LibraryBuilderImpl(Uri fileUri, this.scope, this.exportScope)
      : scopeBuilder = new ScopeBuilder(scope),
        exportScopeBuilder = new ScopeBuilder(exportScope),
        super(null, -1, fileUri);

  @override
  bool get isSynthetic => false;

  // Deliberately unrelated return type to statically detect more accidental
  // use until Builder.target is fully retired.
  @override
  UnrelatedTarget get target => unsupported(
      "LibraryBuilder.target is deprecated. "
      "Use LibraryBuilder.library instead.",
      charOffset,
      fileUri);

  /// Set the langauge version to a specific non-null major and minor version.
  ///
  /// If the language version has previously been explicitly set set (i.e. with
  /// [explicit] set to true), any subsequent call (explicit or not) should be
  /// ignored.
  /// Multiple calls with [explicit] set to false should be allowed though.
  ///
  /// The main idea is that the .packages file specifies a default language
  /// version, but that the library can have source code that specifies another
  /// one which should be supported, but specifying several in code should not
  /// change anything.
  ///
  /// [offset] and [length] refers to the offset and length of the source code
  /// specifying the language version.
  @override
  void setLanguageVersion(int major, int minor,
      {int offset: 0, int length, bool explicit});

  @override
  Builder get parent => null;

  @override
  bool get isPart => false;

  @override
  String get debugName => "LibraryBuilder";

  @override
  Loader get loader;

  @override
  int get modifiers => 0;

  @override
  Uri get uri;

  @override
  Iterator<Builder> get iterator {
    return new LibraryLocalDeclarationIterator(this);
  }

  @override
  NameIterator get nameIterator {
    return new LibraryLocalDeclarationNameIterator(this);
  }

  @override
  void addExporter(
      LibraryBuilder exporter, List<Combinator> combinators, int charOffset) {
    exporters.add(new Export(exporter, this, combinators, charOffset));
  }

  @override
  FormattedMessage addProblem(
      Message message, int charOffset, int length, Uri fileUri,
      {bool wasHandled: false,
      List<LocatedMessage> context,
      Severity severity,
      bool problemOnLibrary: false}) {
    fileUri ??= this.fileUri;

    return loader.addProblem(message, charOffset, length, fileUri,
        wasHandled: wasHandled,
        context: context,
        severity: severity,
        problemOnLibrary: true);
  }

  @override
  bool addToExportScope(String name, Builder member, [int charOffset = -1]) {
    if (name.startsWith("_")) return false;
    if (member is PrefixBuilder) return false;
    Map<String, Builder> map =
        member.isSetter ? exportScope.setters : exportScope.local;
    Builder existing = map[name];
    if (existing == member) return false;
    if (existing != null) {
      Builder result = computeAmbiguousDeclaration(
          name, existing, member, charOffset,
          isExport: true);
      map[name] = result;
      return result != existing;
    } else {
      map[name] = member;
    }
    return true;
  }

  @override
  int finishDeferredLoadTearoffs() => 0;

  @override
  int finishForwarders() => 0;

  @override
  int finishNativeMethods() => 0;

  @override
  int finishPatchMethods() => 0;

  @override
  MemberBuilder getConstructor(String className,
      {String constructorName, bool bypassLibraryPrivacy: false}) {
    constructorName ??= "";
    if (constructorName.startsWith("_") && !bypassLibraryPrivacy) {
      return internalProblem(
          templateInternalProblemPrivateConstructorAccess
              .withArguments(constructorName),
          -1,
          null);
    }
    Builder cls = (bypassLibraryPrivacy ? scope : exportScope)
        .lookup(className, -1, null);
    if (cls is ClassBuilder) {
      // TODO(ahe): This code is similar to code in `endNewExpression` in
      // `body_builder.dart`, try to share it.
      MemberBuilder constructor =
          cls.findConstructorOrFactory(constructorName, -1, null, this);
      if (constructor == null) {
        // Fall-through to internal error below.
      } else if (constructor.isConstructor) {
        if (!cls.isAbstract) {
          return constructor;
        }
      } else if (constructor.isFactory) {
        return constructor;
      }
    }
    throw internalProblem(
        templateInternalProblemConstructorNotFound.withArguments(
            "$className.$constructorName", uri),
        -1,
        null);
  }

  @override
  int finishTypeVariables(ClassBuilder object, TypeBuilder dynamicType) => 0;

  @override
  int computeDefaultTypes(TypeBuilder dynamicType, TypeBuilder bottomType,
      ClassBuilder objectClass) {
    return 0;
  }

  @override
  void becomeCoreLibrary() {
    if (scope.local["dynamic"] == null) {
      addSyntheticDeclarationOfDynamic();
    }
  }

  @override
  Builder lookupLocalMember(String name, {bool required: false}) {
    Builder builder = scope.local[name];
    if (required && builder == null) {
      internalProblem(
          templateInternalProblemNotFoundIn.withArguments(
              name, fullNameForErrors),
          -1,
          null);
    }
    return builder;
  }

  @override
  Builder lookup(String name, int charOffset, Uri fileUri) {
    return scope.lookup(name, charOffset, fileUri);
  }

  @override
  void applyPatches() {
    if (!isPatch) return;
    unsupported("${runtimeType}.applyPatches", -1, fileUri);
  }

  @override
  void recordAccess(int charOffset, int length, Uri fileUri) {}

  @override
  void buildOutlineExpressions() {}

  @override
  List<FieldBuilder> takeImplicitlyTypedFields() => null;

  // TODO(38287): Compute the predicate using the library version instead.
  @override
  bool get isNonNullableByDefault => loader.target.enableNonNullable;

  @override
  Nullability get nullable {
    return isNonNullableByDefault ? Nullability.nullable : Nullability.legacy;
  }

  @override
  Nullability get nonNullable {
    return isNonNullableByDefault
        ? Nullability.nonNullable
        : Nullability.legacy;
  }

  @override
  Nullability nullableIfTrue(bool isNullable) {
    if (isNonNullableByDefault) {
      return isNullable ? Nullability.nullable : Nullability.nonNullable;
    }
    return Nullability.legacy;
  }

  @override
  NullabilityBuilder get nullableBuilder {
    return isNonNullableByDefault
        ? const NullabilityBuilder.nullable()
        : const NullabilityBuilder.omitted();
  }

  @override
  NullabilityBuilder get nonNullableBuilder {
    return const NullabilityBuilder.omitted();
  }

  @override
  NullabilityBuilder nullableBuilderIfTrue(bool isNullable) {
    return isNullable
        ? const NullabilityBuilder.nullable()
        : const NullabilityBuilder.omitted();
  }
}

class LibraryLocalDeclarationIterator implements Iterator<Builder> {
  final LibraryBuilder library;
  final Iterator<Builder> iterator;

  LibraryLocalDeclarationIterator(this.library)
      : iterator = library.scope.iterator;

  Builder get current => iterator.current;

  bool moveNext() {
    while (iterator.moveNext()) {
      if (current.parent == library) return true;
    }
    return false;
  }
}

class LibraryLocalDeclarationNameIterator implements NameIterator {
  final LibraryBuilder library;
  final NameIterator iterator;

  LibraryLocalDeclarationNameIterator(this.library)
      : iterator = library.scope.nameIterator;

  Builder get current => iterator.current;

  String get name => iterator.name;

  bool moveNext() {
    while (iterator.moveNext()) {
      if (current.parent == library) return true;
    }
    return false;
  }
}
