// 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.

part of dart_backend;

typedef bool IsSafeToRemoveTypeDeclarations(
    Map<ClassElement, Iterable<Element>> classMembers);
typedef void ElementCallback<E>(E element);
typedef void ElementPostProcessFunction(
    AstElement element, ElementAst elementAst,
    ElementCallback<TypedefElement> typedefCallback,
    ElementCallback<ClassElement> classCallback);
typedef ElementAst ComputeElementAstFunction(AstElement element);
typedef bool ElementFilter(Element element);
typedef List<Element> ElementSorter(Iterable<Element> elements);

/// Output engine for dart2dart that is shared between the dart2js and the
/// analyzer implementations of dart2dart.
class DartOutputter {
  final DiagnosticListener listener;
  final CompilerOutputProvider outputProvider;
  final bool forceStripTypes;

  // TODO(antonm): make available from command-line options.
  final bool outputAst = false;
  final bool enableMinification;

  /// If `true`, libraries are generated into separate files.
  final bool multiFile;

  /// Internal structures accessible for tests and logging.
  // TODO(johnniwinther): Clean this up.
  PlaceholderRenamer renamer;
  MainOutputGenerator output;
  LibraryInfo libraryInfo;
  ElementInfo elementInfo;

  // TODO(johnniwinther): Support recompilation.
  DartOutputter(this.listener, this.outputProvider,
                {bool this.forceStripTypes: false,
                 bool this.enableMinification: false,
                 bool this.multiFile: false});

  /// Generate Dart code for the program starting at [mainFunction].
  ///
  /// [libraries] is the set of all libraries (user/package/sdk) that are
  /// referenced in the program.
  ///
  /// [instantiatedClasses] is the set of classes that are potentially
  /// instantiated in the program.
  ///
  /// [resolvedElements] is the set of methods, constructors, and fields that
  /// are potentially accessed/called in the program.
  ///
  /// The [sortElements] function is used to sort [instantiatedClasses] and
  /// [resolvedElements] in the generated output.
  ///
  /// Returns the total size of the generated code.
  int assembleProgram({
      MirrorRenamer mirrorRenamer: const MirrorRenamer(),
      Iterable<LibraryElement> libraries,
      Iterable<Element> instantiatedClasses,
      Iterable<Element> resolvedElements,
      Iterable<ClassElement> usedTypeLiterals: const <ClassElement>[],
      FunctionElement mainFunction,
      Uri outputUri,
      ElementPostProcessFunction postProcessElementAst,
      ComputeElementAstFunction computeElementAst,
      ElementFilter shouldOutput,
      IsSafeToRemoveTypeDeclarations isSafeToRemoveTypeDeclarations,
      ElementSorter sortElements}) {

    assert(invariant(NO_LOCATION_SPANNABLE, libraries != null,
        message: "'libraries' must be non-null."));
    assert(invariant(NO_LOCATION_SPANNABLE, instantiatedClasses != null,
        message: "'instantiatedClasses' must be non-null."));
    assert(invariant(NO_LOCATION_SPANNABLE, resolvedElements != null,
        message: "'resolvedElements' must be non-null."));
    assert(invariant(NO_LOCATION_SPANNABLE, mainFunction != null,
        message: "'mainFunction' must be non-null."));
    assert(invariant(NO_LOCATION_SPANNABLE, computeElementAst != null,
        message: "'computeElementAst' must be non-null."));
    assert(invariant(NO_LOCATION_SPANNABLE, shouldOutput != null,
        message: "'shouldOutput' must be non-null."));
    assert(invariant(NO_LOCATION_SPANNABLE,
        isSafeToRemoveTypeDeclarations != null,
        message: "'isSafeToRemoveTypeDeclarations' must be non-null."));

    if (sortElements == null) {
      // Ensure deterministic output order.
      sortElements = (Iterable<Element> elements) {
        List<Element> list = elements.toList();
        list.sort((Element a, Element b) => a.name.compareTo(b.name));
        return list;
      };
    }

    libraryInfo = LibraryInfo.processLibraries(
        listener, libraries, resolvedElements);

    elementInfo = ElementInfoProcessor.createElementInfo(
        instantiatedClasses,
        resolvedElements,
        usedTypeLiterals,
        postProcessElementAst: postProcessElementAst,
        parseElementAst: computeElementAst,
        shouldOutput: shouldOutput,
        sortElements: sortElements);

    PlaceholderCollector collector = collectPlaceholders(
        listener,
        mirrorRenamer,
        mainFunction,
        libraryInfo,
        elementInfo);

    renamer = createRenamer(
        collector,
        libraryInfo,
        elementInfo,
        enableMinification: enableMinification,
        forceStripTypes: forceStripTypes,
        isSafeToRemoveTypeDeclarations: isSafeToRemoveTypeDeclarations);

    if (outputAst) {
      String code = astOutput(listener, elementInfo);
      outputProvider("", "dart")
                 ..add(code)
                 ..close();
      return code.length;
    } else {
      output = new MainOutputGenerator();
      return output.generateCode(
          libraryInfo,
          elementInfo,
          collector,
          renamer,
          mainFunction,
          outputUri,
          outputProvider,
          mirrorRenamer,
          multiFile: multiFile,
          forceStripTypes: forceStripTypes,
          enableMinification: enableMinification);
    }
  }

  static PlaceholderCollector collectPlaceholders(
      DiagnosticListener listener,
      MirrorRenamer mirrorRenamer,
      FunctionElement mainFunction,
      LibraryInfo libraryInfo,
      ElementInfo elementInfo) {
    // Create all necessary placeholders.
    PlaceholderCollector collector = new PlaceholderCollector(
        listener,
        mirrorRenamer,
        libraryInfo.fixedDynamicNames,
        elementInfo.elementAsts,
        mainFunction);

    makePlaceholders(element) {
      collector.collect(element);

      if (element.isClass && !element.isEnumClass) {
        elementInfo.classMembers[element].forEach(makePlaceholders);
      }
    }
    elementInfo.topLevelElements.forEach(makePlaceholders);
    return collector;
  }

  static PlaceholderRenamer createRenamer(
      PlaceholderCollector collector,
      LibraryInfo libraryInfo,
      ElementInfo elementInfo,
      {bool enableMinification: false,
       bool forceStripTypes: false,
       isSafeToRemoveTypeDeclarations}) {
    // Create renames.
    bool shouldCutDeclarationTypes = forceStripTypes
        || (enableMinification
            && isSafeToRemoveTypeDeclarations(elementInfo.classMembers));

    PlaceholderRenamer placeholderRenamer = new PlaceholderRenamer(
        libraryInfo.fixedDynamicNames,
        libraryInfo.fixedStaticNames,
        libraryInfo.reexportingLibraries,
        cutDeclarationTypes: shouldCutDeclarationTypes,
        enableMinification: enableMinification);

    placeholderRenamer.computeRenames(collector);
    return placeholderRenamer;
  }

  static String astOutput(DiagnosticListener listener,
                          ElementInfo elementInfo) {
    // TODO(antonm): Ideally XML should be a separate backend.
    // TODO(antonm): obey renames and minification, at least as an option.
    StringBuffer sb = new StringBuffer();
    outputElement(element) {
      sb.write(element.parseNode(listener).toDebugString());
    }

    // Emit XML for AST instead of the program.
    for (Element topLevel in elementInfo.topLevelElements) {
      if (topLevel.isClass &&
          !elementInfo.emitNoMembersFor.contains(topLevel)) {
        // TODO(antonm): add some class info.
        elementInfo.classMembers[topLevel].forEach(outputElement);
      } else {
        outputElement(topLevel);
      }
    }
    return '<Program>\n$sb</Program>\n';
  }
}

class LibraryInfo {
  final Set<String> fixedStaticNames;
  final Set<String> fixedDynamicNames;
  final Map<Element, LibraryElement> reexportingLibraries;
  final List<LibraryElement> userLibraries;

  LibraryInfo(this.fixedStaticNames,
              this.fixedDynamicNames,
              this.reexportingLibraries,
              this.userLibraries);

  static LibraryInfo processLibraries(
      DiagnosticListener listener,
      Iterable<LibraryElement> libraries,
      Iterable<AstElement> resolvedElements) {
    Set<String> fixedStaticNames = new Set<String>();
    Set<String> fixedDynamicNames = new Set<String>();
    Map<Element, LibraryElement> reexportingLibraries =
          <Element, LibraryElement>{};
    List<LibraryElement> userLibraries = <LibraryElement>[];
    // Conservatively traverse all platform libraries and collect member names.
    // TODO(antonm): ideally we should only collect names of used members,
    // however as of today there are problems with names of some core library
    // interfaces, most probably for interfaces of literals.

    for (LibraryElement library in libraries) {
      if (!library.isPlatformLibrary) {
        userLibraries.add(library);
        continue;
      }
      library.forEachLocalMember((Element element) {
        if (element.isClass) {
          ClassElement classElement = element;
          assert(invariant(classElement, classElement.isResolved,
              message: "Unresolved platform class."));
          classElement.forEachLocalMember((member) {
            if (member.isInstanceMember) {
              fixedDynamicNames.add(member.name);
            } else {
              fixedStaticNames.add(member.name);
            }
          });
        }
        // Even class names are added due to a delicate problem we have:
        // if one imports dart:core with a prefix, we cannot tell prefix.name
        // from dynamic invocation (alas!).  So we'd better err on preserving
        // those names.
        fixedStaticNames.add(element.name);
      });

      library.forEachExport((Element export) {
        if (!library.isInternalLibrary &&
            export.library.isInternalLibrary) {
          // If an element of an internal library is reexported by a platform
          // library, we have to import the reexporting library instead of the
          // internal library, because the internal library is an
          // implementation detail of dart2js.
          reexportingLibraries[export] = library;
        }
      });
    }

    // Map to keep track of names of enum classes. Since these cannot be renamed
    // we ensure that they are unique.
    Map<String, ClassElement> enumClassMap = <String, ClassElement>{};

    // As of now names of named optionals are not renamed. Therefore add all
    // field names used as named optionals into [fixedMemberNames].
    for (final element in resolvedElements) {
      if (!element.isConstructor) continue;
      for (ParameterElement parameter in element.parameters) {
        if (parameter.isInitializingFormal && parameter.isNamed) {
          fixedDynamicNames.add(parameter.name);
        }
      }
      ClassElement cls = element.enclosingClass;
      if (cls != null && cls.isEnumClass) {
        fixedDynamicNames.add('index');

        ClassElement existingEnumClass =
            enumClassMap.putIfAbsent(cls.name, () => cls);
        if (existingEnumClass != cls) {
          listener.reportError(
              listener.createMessage(
                  cls,
                  MessageKind.GENERIC,
                  {'text': "Duplicate enum names are not supported "
                           "in dart2dart."}),
          <DiagnosticMessage>[
              listener.createMessage(
                  existingEnumClass,
                  MessageKind.GENERIC,
                  {'text': "This is the other declaration of '${cls.name}'."}),
          ]);
        }
      }
    }

    fixedStaticNames.addAll(enumClassMap.keys);

    // The VM will automatically invoke the call method of objects
    // that are invoked as functions. Make sure to not rename that.
    fixedDynamicNames.add('call');

    return new LibraryInfo(
        fixedStaticNames, fixedDynamicNames,
        reexportingLibraries, userLibraries);
  }
}

class ElementInfo {
  final Map<Element, ElementAst> elementAsts;
  final Iterable<Element> topLevelElements;
  final Map<ClassElement, Iterable<Element>> classMembers;
  final Iterable<ClassElement> emitNoMembersFor;

  ElementInfo(this.elementAsts,
              this.topLevelElements,
              this.classMembers,
              this.emitNoMembersFor);
}

class ElementInfoProcessor implements ElementInfo {
  final Map<Element, ElementAst> elementAsts = new Map<Element, ElementAst>();
  final Set<Element> topLevelElements = new Set<Element>();
  final Map<ClassElement, Set<Element>> classMembers =
      new Map<ClassElement, Set<Element>>();
  final Set<ClassElement> emitNoMembersFor = new Set<ClassElement>();
  final ElementPostProcessFunction postProcessElementAst;
  final ComputeElementAstFunction parseElementAst;
  final ElementFilter shouldOutput;

  ElementInfoProcessor(
      {this.postProcessElementAst,
       this.parseElementAst,
       this.shouldOutput});

  static ElementInfo createElementInfo(
      Iterable<ClassElement> instantiatedClasses,
      Iterable<AstElement> resolvedElements,
      Iterable<ClassElement> usedTypeLiterals,
      {ElementPostProcessFunction postProcessElementAst,
       ComputeElementAstFunction parseElementAst,
       ElementFilter shouldOutput,
       ElementSorter sortElements}) {
    ElementInfoProcessor processor = new ElementInfoProcessor(
        postProcessElementAst: postProcessElementAst,
        parseElementAst: parseElementAst,
        shouldOutput: shouldOutput);
    return processor.process(
        instantiatedClasses, resolvedElements, usedTypeLiterals,
        sortElements: sortElements);
  }

  ElementInfo process(Iterable<ClassElement> instantiatedClasses,
                      Iterable<AstElement> resolvedElements,
                      Iterable<ClassElement> usedTypeLiterals,
                      {ElementSorter sortElements}) {
    // Build all top level elements to emit and necessary class members.
    instantiatedClasses.where(shouldOutput).forEach(addClass);
    resolvedElements.where(shouldOutput).forEach(addMember);
    usedTypeLiterals.forEach((ClassElement element) {
      if (shouldOutput(element)) {
        if (!topLevelElements.contains(element)) {
          // The class is only referenced by type literals.
          emitNoMembersFor.add(element);
        }
        addClass(element);
      }
    });

    // Sort elements.
    List<Element> sortedTopLevels = sortElements(topLevelElements);
    Map<ClassElement, List<Element>> sortedClassMembers =
        new Map<ClassElement, List<Element>>();
    classMembers.forEach((classElement, members) {
      sortedClassMembers[classElement] = sortElements(members);
    });

    return new ElementInfo(
        elementAsts, sortedTopLevels, sortedClassMembers, emitNoMembersFor);
  }

  void processElement(Element element, ElementAst elementAst) {
    if (postProcessElementAst != null) {
      postProcessElementAst(element, elementAst,
                            newTypedefElementCallback,
                            newClassElementCallback);
    }
    elementAsts[element] = elementAst;
  }

  void addTopLevel(AstElement element, ElementAst elementAst) {
    if (topLevelElements.contains(element)) return;
    topLevelElements.add(element);
    processElement(element, elementAst);
  }

  void addClass(ClassElement classElement) {
    TreeElements treeElements = new TreeElementMapping(classElement);
    backend2frontend.TreePrinter treePrinter =
        new backend2frontend.TreePrinter(treeElements);
    Node node = treePrinter.makeNodeForClassElement(classElement);
    addTopLevel(classElement, new ElementAst(node, treeElements));
    classMembers.putIfAbsent(classElement, () => new Set());
  }

  void newTypedefElementCallback(TypedefElement element) {
    if (!shouldOutput(element)) return;
    TreeElements treeElements = new TreeElementMapping(element);
    backend2frontend.TreePrinter treePrinter =
        new backend2frontend.TreePrinter(treeElements);
    Node node = treePrinter.makeTypedef(element);
    addTopLevel(element, new ElementAst(node, treeElements));
  }

  void newClassElementCallback(ClassElement classElement) {
    if (!shouldOutput(classElement)) return;
    addClass(classElement);
  }

  void addMember(element) {
    if (element.isClassMember) {
      ClassElement enclosingClass = element.enclosingClass;
      assert(enclosingClass.isClass);
      assert(shouldOutput(enclosingClass));
      addClass(enclosingClass);
      classMembers[enclosingClass].add(element);
      if (enclosingClass.isEnumClass) return;
      processElement(element, parseElementAst(element));
    } else {
      if (element.isTopLevel) {
        addTopLevel(element, parseElementAst(element));
      }
    }
  }
}

/// Main output generator for [DartOutputter] that emits dart code through a
/// [CompilerOutputProvider].
class MainOutputGenerator {
  final Map<ClassNode, List<Node>> memberNodes =
       new Map<ClassNode, List<Node>>();
  final List<Node> topLevelNodes = <Node>[];

  /// Generates the code and returns the total size.
  int generateCode(
      LibraryInfo libraryInfo,
      ElementInfo elementInfo,
      PlaceholderCollector collector,
      PlaceholderRenamer placeholderRenamer,
      FunctionElement mainFunction,
      Uri outputUri,
      CompilerOutputProvider outputProvider,
      MirrorRenamer mirrorRenamer,
      {bool multiFile: false,
       bool forceStripTypes: false,
       bool enableMinification: false}) {
    for (Element element in elementInfo.topLevelElements) {
      topLevelNodes.add(elementInfo.elementAsts[element].ast);
      if (element.isClass) {
        ClassElement cls = element;
        if (cls.isMixinApplication || cls.isEnumClass) {
          continue;
        }
        final members = <Node>[];
        for (Element member in elementInfo.classMembers[cls]) {
          members.add(elementInfo.elementAsts[member].ast);
        }
        memberNodes[elementInfo.elementAsts[cls].ast] = members;
      }
    }

    mirrorRenamer.addRenames(placeholderRenamer.renames,
                             topLevelNodes, collector);

    Map<LibraryElement, String> outputPaths = new Map<LibraryElement, String>();
    Map<LibraryElement, EmitterUnparser> unparsers =
        new Map<LibraryElement, EmitterUnparser>();

    // The single unparser used if we collect all the output in one file.
    EmitterUnparser mainUnparser = multiFile
        ? null
        : new EmitterUnparser(placeholderRenamer.renames,
            stripTypes: forceStripTypes,
            minify: enableMinification);

    if (multiFile) {
      // TODO(sigurdm): Factor handling of library-paths out from emitting.
      String mainName = outputUri.pathSegments.last;
      String mainBaseName = mainName.endsWith(".dart")
          ? mainName.substring(0, mainName.length - 5)
          : mainName;
      // Map each library to a path based on the uri of the original
      // library and [compiler.outputUri].
      Set<String> usedLibraryPaths = new Set<String>();
      for (LibraryElement library in libraryInfo.userLibraries) {
        if (library == mainFunction.library) {
          outputPaths[library] = mainBaseName;
        } else {
          List<String> names =
              library.canonicalUri.pathSegments.last.split(".");
          if (names.last == "dart") {
            names = names.sublist(0, names.length - 1);
          }
          outputPaths[library] =
              "$mainBaseName.${makeUnique(names.join("."), usedLibraryPaths)}";
        }
      }

      /// Rewrites imports/exports to refer to the paths given in [outputPaths].
      for(LibraryElement outputLibrary in libraryInfo.userLibraries) {
        EmitterUnparser unparser = new EmitterUnparser(
            placeholderRenamer.renames,
            stripTypes: forceStripTypes,
            minify: enableMinification);
        unparsers[outputLibrary] = unparser;
        if (outputLibrary.hasLibraryName) {
          unparser.unparseLibraryName(outputLibrary.libraryName);
        }
        for (ImportElement import in outputLibrary.imports) {
          LibraryElement libraryElement = import.importedLibrary;
          String uri = outputPaths.containsKey(libraryElement)
              ? "${outputPaths[libraryElement]}.dart"
              : libraryElement.canonicalUri.toString();
          unparser.unparseImportTag(uri);
        }
        for (ExportElement export in outputLibrary.exports) {
          LibraryElement libraryElement = export.exportedLibrary;
          String uri = outputPaths.containsKey(libraryElement)
              ? "${outputPaths[libraryElement]}.dart"
              : libraryElement.canonicalUri.toString();
          unparser.unparseExportTag(uri);
        }
      }
    } else {
      placeholderRenamer.platformImports.forEach(
          (LibraryElement library, String prefix) {
        assert(library.isPlatformLibrary && !library.isInternalLibrary);
        mainUnparser.unparseImportTag(library.canonicalUri.toString());
        if (prefix != null) {
          // Adding a prefixed import because (some) top-level access need
          // it to avoid shadowing.
          // TODO(johnniwinther): Avoid prefix-less import if not needed.
          mainUnparser.unparseImportTag(library.canonicalUri.toString(),
                                        prefix: prefix);
        }
      });
    }

    for (int i = 0; i < elementInfo.topLevelElements.length; i++) {
      Element element = elementInfo.topLevelElements.elementAt(i);
      Node node = topLevelNodes[i];
      Unparser unparser = multiFile ? unparsers[element.library] : mainUnparser;
      if (node is ClassNode) {
        // TODO(smok): Filter out default constructors here.
        unparser.unparseClassWithBody(node, memberNodes[node]);
      } else {
        unparser.unparse(node);
      }
      unparser.newline();
    }

    int totalSize = 0;
    if (multiFile) {
      for(LibraryElement outputLibrary in libraryInfo.userLibraries) {
        // TODO(sigurdm): Make the unparser output directly into the buffer
        // instead of caching in `.result`.
        String code = unparsers[outputLibrary].result;
        totalSize += code.length;
        outputProvider(outputPaths[outputLibrary], "dart")
             ..add(code)
             ..close();
      }
    } else {
      String code = mainUnparser.result;
      outputProvider("", "dart")
           ..add(code)
           ..close();

      totalSize = code.length;
    }

    return totalSize;
  }
}