// Copyright (c) 2014, 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 resolution.deferred_load;

import '../common.dart';
import '../compiler.dart' show Compiler;
import '../constants/expressions.dart' show ConstantExpression;
import '../constants/values.dart'
    show ConstantValue, ConstructedConstantValue, StringConstantValue;
import '../deferred_load.dart';
import '../elements/elements.dart'
    show
        AstElement,
        AccessorElement,
        ClassElement,
        ConstructorElement,
        Element,
        ExportElement,
        ImportElement,
        LibraryElement,
        MemberElement,
        MetadataAnnotation,
        PrefixElement,
        ResolvedAstKind,
        TypedefElement;
import '../elements/resolution_types.dart';
import '../js_backend/js_backend.dart' show JavaScriptBackend;
import '../resolution/resolution.dart' show AnalyzableElementX;
import '../resolution/tree_elements.dart' show TreeElements;
import '../tree/tree.dart' as ast;
import '../util/util.dart' show Setlet;
import 'tree_elements.dart' show TreeElements;

class AstDeferredLoadTask extends DeferredLoadTask {
  /// DeferredLibrary from dart:async
  ClassElement get deferredLibraryClass =>
      compiler.resolution.commonElements.deferredLibraryClass;

  JavaScriptBackend get backend => compiler.backend;

  AstDeferredLoadTask(Compiler compiler) : super(compiler);

  Iterable<ImportElement> importsTo(
      covariant Element element, covariant LibraryElement library) {
    if (element.isClassMember) {
      element = element.enclosingClass;
    }
    if (element.isAccessor) {
      element = (element as AccessorElement).abstractField;
    }
    return library.getImportsFor(element);
  }

  void checkForDeferredErrorCases(covariant LibraryElement library) {
    var usedPrefixes = new Setlet<String>();
    // The last deferred import we saw with a given prefix (if any).
    var prefixDeferredImport = new Map<String, ImportElement>();
    for (ImportElement import in library.imports) {
      _detectOldSyntax(import);
      _detectDuplicateErrorCases(import, usedPrefixes, prefixDeferredImport);
    }
  }

  /// Give an error if the old annotation-based syntax has been used.
  void _detectOldSyntax(ImportElement import) {
    List<MetadataAnnotation> metadataList = import.metadata;
    if (metadataList != null) {
      for (MetadataAnnotation metadata in metadataList) {
        metadata.ensureResolved(compiler.resolution);
        ConstantValue value =
            compiler.constants.getConstantValue(metadata.constant);
        ResolutionDartType type =
            value.getType(compiler.resolution.commonElements);
        Element element = type.element;
        if (element == deferredLibraryClass) {
          reporter.reportErrorMessage(import, MessageKind.DEFERRED_OLD_SYNTAX);
        }
      }
    }
  }

  /// Detect duplicate prefixes of deferred libraries.
  ///
  /// There are 4 cases of duplicate prefixes:
  ///   1.
  ///       import "lib.dart" deferred as a;
  ///       import "lib2.dart" deferred as a;
  ///
  ///   2.
  ///       import "lib.dart" deferred as a;
  ///       import "lib2.dart" as a;
  ///
  ///   3.
  ///       import "lib.dart" as a;
  ///       import "lib2.dart" deferred as a;
  ///
  ///   4.
  ///       import "lib.dart" as a;
  ///       import "lib2.dart" as a;
  ///
  /// We must be able to signal error for case 1, 2, 3, but accept case 4.
  void _detectDuplicateErrorCases(
      ImportElement import,
      Set<String> usedPrefixes,
      Map<String, ImportElement> prefixDeferredImport) {
    String prefix = import.name;
    // The last import we saw with the same prefix.
    ImportElement previousDeferredImport = prefixDeferredImport[prefix];
    if (import.isDeferred) {
      if (prefix == null) {
        reporter.reportErrorMessage(
            import, MessageKind.DEFERRED_LIBRARY_WITHOUT_PREFIX);
      } else {
        prefixDeferredImport[prefix] = import;
      }
    }
    if (prefix != null) {
      if (previousDeferredImport != null ||
          (import.isDeferred && usedPrefixes.contains(prefix))) {
        ImportElement failingImport =
            (previousDeferredImport != null) ? previousDeferredImport : import;
        reporter.reportErrorMessage(failingImport.prefix,
            MessageKind.DEFERRED_LIBRARY_DUPLICATE_PREFIX);
      }
      usedPrefixes.add(prefix);
    }
  }

  @override
  void collectConstantsFromMetadata(
      covariant AstElement element, Set<ConstantValue> constants) {
    for (MetadataAnnotation metadata in element.metadata) {
      ConstantValue constant =
          backend.constants.getConstantValueForMetadata(metadata);
      if (constant != null) constants.add(constant);
    }
  }

  @override
  void collectConstantsInBody(
      covariant AstElement element, Set<ConstantValue> constants) {
    if (element.resolvedAst.kind != ResolvedAstKind.PARSED) return;

    TreeElements treeElements = element.resolvedAst.elements;
    assert(treeElements != null);

    Set<ast.Node> metadataNodes = element.implementation.metadata
        .map((m) => m.node)
        .toSet()
          ..addAll(element.declaration.metadata.map((m) => m.node));

    // TODO(johnniwinther): Add only expressions that are actually needed.
    // Currently we have some noise here: Some potential expressions are
    // seen that should never be added (for instance field initializers
    // in constant constructors, like `this.field = parameter`). And some
    // implicit constant expression are seen that we should be able to add
    // (like primitive constant literals like `true`, `"foo"` and `0`).
    // See dartbug.com/26406 for context.
    treeElements
        .forEachConstantNode((ast.Node node, ConstantExpression expression) {
      if (metadataNodes.contains(node)) return;
      if (compiler.serialization.isDeserialized(element)) {
        if (!expression.isPotential) {
          // Enforce evaluation of [expression].
          backend.constants.getConstantValue(expression);
        }
      }

      // Explicitly depend on the backend constants.
      if (backend.constants.hasConstantValue(expression)) {
        ConstantValue value = backend.constants.getConstantValue(expression);
        assert(
            value != null,
            failedAt(
                node,
                "Constant expression without value: "
                "${expression.toStructuredText()}."));
        constants.add(value);
      } else {
        assert(
            expression.isImplicit || expression.isPotential,
            failedAt(
                node,
                "Unexpected unevaluated constant expression: "
                "${expression.toStructuredText()}."));
      }
    });
  }

  void addDeferredMirrorElements(WorkQueue queue) {
    for (ImportElement deferredImport in allDeferredImports) {
      addMirrorElementsForLibrary(queue, deferredImport.importedLibrary,
          importSets.singleton(deferredImport));
    }
  }

  void addMirrorElementsForLibrary(
      WorkQueue queue, covariant LibraryElement root, ImportSet newSet) {
    void handleElementIfResolved(Element element) {
      // If an element is the target of a MirrorsUsed annotation but never used
      // It will not be resolved, and we should not call isNeededForReflection.
      // TODO(sigurdm): Unresolved elements should just answer false when
      // asked isNeededForReflection. Instead an internal error is triggered.
      // So we have to filter them out here.
      if (element is AnalyzableElementX && !element.hasTreeElements) return;

      bool isAccessibleByReflection(Element element) {
        if (element.isLibrary) {
          return false;
        } else if (element.isClass) {
          ClassElement cls = element;
          return compiler.backend.mirrorsData
              .isClassAccessibleByReflection(cls);
        } else if (element.isTypedef) {
          TypedefElement typedef = element;
          return compiler.backend.mirrorsData
              .isTypedefAccessibleByReflection(typedef);
        } else {
          MemberElement member = element;
          return compiler.backend.mirrorsData
              .isMemberAccessibleByReflection(member);
        }
      }

      if (isAccessibleByReflection(element)) {
        queue.addElement(element, newSet, isMirrorUsage: true);
      }
    }

    // For each deferred import we analyze all elements reachable from the
    // imported library through non-deferred imports.
    void handleLibrary(LibraryElement library) {
      library.implementation.forEachLocalMember((Element element) {
        handleElementIfResolved(element);
      });

      void processMetadata(Element element) {
        for (MetadataAnnotation metadata in element.metadata) {
          ConstantValue constant =
              backend.constants.getConstantValueForMetadata(metadata);
          if (constant != null) {
            queue.addConstant(constant, newSet);
          }
        }
      }

      processMetadata(library);
      library.imports.forEach(processMetadata);
      library.exports.forEach(processMetadata);
    }

    _nonDeferredReachableLibraries(root).forEach(handleLibrary);
  }

  /// Returns the transitive closure of all libraries that are imported
  /// from root without DeferredLibrary annotations.
  Set<LibraryElement> _nonDeferredReachableLibraries(LibraryElement root) {
    Set<LibraryElement> result = new Set<LibraryElement>();

    void traverseLibrary(LibraryElement library) {
      if (result.contains(library)) return;
      result.add(library);

      iterateDependencies(LibraryElement library) {
        for (ImportElement import in library.imports) {
          if (!import.isDeferred) {
            LibraryElement importedLibrary = import.importedLibrary;
            traverseLibrary(importedLibrary);
          }
        }
        for (ExportElement export in library.exports) {
          LibraryElement exportedLibrary = export.exportedLibrary;
          traverseLibrary(exportedLibrary);
        }
      }

      iterateDependencies(library);
      if (library.isPatched) {
        iterateDependencies(library.implementation);
      }
    }

    traverseLibrary(root);
    result.add(compiler.resolution.commonElements.coreLibrary);
    return result;
  }

  /// If [send] is a static send with a deferred element, returns the
  /// [PrefixElement] that the first prefix of the send resolves to.
  /// Otherwise returns null.
  ///
  /// Precondition: send must be static.
  ///
  /// Example:
  ///
  /// import "a.dart" deferred as a;
  ///
  /// main() {
  ///   print(a.loadLibrary.toString());
  ///   a.loadLibrary().then((_) {
  ///     a.run();
  ///     a.foo.method();
  ///   });
  /// }
  ///
  /// Returns null for a.loadLibrary() (the special
  /// function loadLibrary is not deferred). And returns the PrefixElement for
  /// a.run() and a.foo.
  /// a.loadLibrary.toString() and a.foo.method() are dynamic sends - and
  /// this functions should not be called on them.
  ImportElement deferredImportElement(ast.Send send, TreeElements elements) {
    Element element = elements[send];
    // The DeferredLoaderGetter is not deferred, therefore we do not return the
    // prefix.
    if (element != null && element.isDeferredLoaderGetter) return null;

    ast.Node firstNode(ast.Node node) {
      if (node is! ast.Send) {
        return node;
      } else {
        ast.Send send = node;
        ast.Node receiver = send.receiver;
        ast.Node receiverFirst = firstNode(receiver);
        if (receiverFirst != null) {
          return receiverFirst;
        } else {
          return firstNode(send.selector);
        }
      }
    }

    ast.Node first = firstNode(send);
    ast.Node identifier = first.asIdentifier();
    if (identifier == null) return null;
    Element maybePrefix = elements[identifier];
    if (maybePrefix != null && maybePrefix.isPrefix) {
      PrefixElement prefixElement = maybePrefix;
      if (prefixElement.isDeferred) {
        return prefixElement.deferredImport;
      }
    }
    return null;
  }

  /// Returns a name for a deferred import.
  // TODO(sigmund): delete support for the old annotation-style syntax.
  String computeImportDeferName(
      covariant ImportElement declaration, Compiler compiler) {
    if (declaration.isDeferred) {
      return super.computeImportDeferName(declaration, compiler);
    }

    String result;
    // Finds the first argument to the [DeferredLibrary] annotation
    List<MetadataAnnotation> metadatas = declaration.metadata;
    assert(metadatas != null);
    for (MetadataAnnotation metadata in metadatas) {
      metadata.ensureResolved(compiler.resolution);
      ConstantValue value =
          compiler.constants.getConstantValue(metadata.constant);
      ResolutionDartType type =
          value.getType(compiler.resolution.commonElements);
      Element element = type.element;
      if (element == compiler.resolution.commonElements.deferredLibraryClass) {
        ConstructedConstantValue constant = value;
        StringConstantValue s = constant.fields.values.single;
        result = s.stringValue;
        break;
      }
    }
    assert(result != null);
    return result;
  }

  bool ignoreEntityInDump(covariant Element element) =>
      // origin element will already be dumped.
      element.isPatch ||
      // redirecting factories are not visible to the kernel ir
      element is ConstructorElement && element.isRedirectingFactory;
}
