// 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(cls, MessageKind.GENERIC,
              {'text': "Duplicate enum names are not supported in dart2dart."});
          listener.reportInfo(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;
  }
}