// Copyright (c) 2012, 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;

Function get _compareNodes =>
    compareBy((n) => n.getBeginToken().charOffset);

typedef String _Renamer(Renamable renamable);
abstract class Renamable {
  const int RENAMABLE_TYPE_ELEMENT = 1;
  const int RENAMABLE_TYPE_MEMBER = 2;
  const int RENAMABLE_TYPE_LOCAL = 3;

  final Set<Node> nodes;
  final _Renamer renamer;

  Renamable(this.nodes, this.renamer);
  int compareTo(Renamable other) {
    int nodesDiff = other.nodes.length.compareTo(this.nodes.length);
    if (nodesDiff != 0) return nodesDiff;
    int typeDiff = this.getTypeId().compareTo(other.getTypeId());
    return typeDiff != 0 ? typeDiff : compareInternals(other);
  }

  int compareInternals(Renamable other);
  int getTypeId();

  String rename() => renamer(this);
}

class ElementRenamable extends Renamable {
  final Element element;

  ElementRenamable(this.element, Set<Node> nodes, _Renamer renamer)
      : super(nodes, renamer);

  int compareInternals(ElementRenamable other) =>
      compareElements(this.element, other.element);
  int getTypeId() => RENAMABLE_TYPE_ELEMENT;
}

class MemberRenamable extends Renamable {
  final String identifier;
  MemberRenamable(this.identifier, Set<Node> nodes, _Renamer renamer)
      : super(nodes, renamer);
  int compareInternals(MemberRenamable other) =>
      this.identifier.compareTo(other.identifier);
  int getTypeId() => RENAMABLE_TYPE_MEMBER;
}

class LocalRenamable extends Renamable {
  LocalRenamable(Set<Node> nodes, _Renamer renamer) : super(nodes, renamer);
  int compareInternals(LocalRenamable other) =>
      _compareNodes(sorted(this.nodes, _compareNodes)[0],
          sorted(other.nodes, _compareNodes)[0]);
  int getTypeId() => RENAMABLE_TYPE_LOCAL;
}

/**
 * Renames only top-level elements that would let to ambiguity if not renamed.
 */
void renamePlaceholders(
    Compiler compiler,
    PlaceholderCollector placeholderCollector,
    Map<Node, String> renames,
    Map<LibraryElement, String> imports,
    Set<String> fixedMemberNames,
    bool cutDeclarationTypes) {
  final Map<LibraryElement, Map<String, String>> renamed
      = new Map<LibraryElement, Map<String, String>>();

  renameNodes(Collection<Node> nodes, renamer) {
    for (Node node in sorted(nodes, _compareNodes)) {
      renames[node] = renamer(node);
    }
  }

  sortedForEach(Map<Element, dynamic> map, f) {
    for (Element element in sortElements(map.keys)) {
      f(element, map[element]);
    }
  }

  String renameType(DartType type, Function renameElement) {
    // TODO(smok): Do not rename type if it is in platform library or
    // js-helpers.
    StringBuffer result = new StringBuffer(renameElement(type.element));
    if (type is InterfaceType) {
      if (!type.isRaw) {
        result.add('<');
        Link<DartType> argumentsLink = type.typeArguments;
        result.add(renameType(argumentsLink.head, renameElement));
        for (Link<DartType> link = argumentsLink.tail; !link.isEmpty;
             link = link.tail) {
          result.add(',');
          result.add(renameType(link.head, renameElement));
        }
        result.add('>');
      }
    }
    return result.toString();
  }

  String renameConstructor(Element element, ConstructorPlaceholder placeholder,
      Function renameString, Function renameElement) {
    assert(element.isConstructor());
    StringBuffer result = new StringBuffer();
    String name = element.name.slowToString();
    if (element.name != element.getEnclosingClass().name) {
      // Named constructor or factory. Is there a more reliable way to check
      // this case?
      if (!placeholder.isRedirectingCall) {
        result.add(renameType(placeholder.type, renameElement));
        result.add('.');
      }
      String prefix = '${element.getEnclosingClass().name.slowToString()}\$';
      if (!name.startsWith(prefix)) {
        // Factory for another interface (that is going away soon).
        compiler.internalErrorOnElement(element,
            "Factory constructors for external interfaces are not supported.");
      }
      name = name.substring(prefix.length);
      if (!element.getLibrary().isPlatformLibrary) {
        name = renameString(element.getLibrary(), name);
      }
      result.add(name);
    } else {
      assert(!placeholder.isRedirectingCall);
      result.add(renameType(placeholder.type, renameElement));
    }
    return result.toString();
  }

  Function makeElementRenamer(rename, generateUniqueName) => (element) {
    assert(Elements.isErroneousElement(element) ||
           Elements.isStaticOrTopLevel(element) ||
           element is TypeVariableElement);
    // TODO(smok): We may want to reuse class static field and method names.
    String originalName = element.name.slowToString();
    LibraryElement library = element.getLibrary();
    if (identical(element.getLibrary(), compiler.coreLibrary)) {
      return originalName;
    }
    if (library.isPlatformLibrary && !library.isInternalLibrary) {
      assert(element.isTopLevel());
      final prefix =
          imports.putIfAbsent(library, () => generateUniqueName('p'));
      return '$prefix.$originalName';
    }

    return rename(library, originalName);
  };

  Function makeRenamer(generateUniqueName) =>
      (library, originalName) =>
          renamed.putIfAbsent(library, () => {})
              .putIfAbsent(originalName,
                  () => generateUniqueName(originalName));

  // Renamer function that takes library and original name and returns a new
  // name for given identifier.
  Function rename;
  Function renameElement;
  // A function that takes original identifier name and generates a new unique
  // identifier.
  Function generateUniqueName;
  if (compiler.enableMinification) {
    MinifyingGenerator generator = new MinifyingGenerator();
    Set<String> forbiddenIdentifiers = new Set<String>.from(['main']);
    forbiddenIdentifiers.addAll(Keyword.keywords.keys);
    forbiddenIdentifiers.addAll(fixedMemberNames);
    generateUniqueName = (_) =>
        generator.generate(forbiddenIdentifiers.contains);
    rename = makeRenamer(generateUniqueName);
    renameElement = makeElementRenamer(rename, generateUniqueName);

    Set<String> allParameterIdentifiers = new Set<String>();
    for (var functionScope in placeholderCollector.functionScopes.values) {
      allParameterIdentifiers.addAll(functionScope.parameterIdentifiers);
    }
    // Build a sorted (by usage) list of local nodes that will be renamed to
    // the same identifier. So the top-used local variables in all functions
    // will be renamed first and will all share the same new identifier.
    List<Set<Node>> allSortedLocals = new List<Set<Node>>();
    for (var functionScope in placeholderCollector.functionScopes.values) {
      // Add current sorted local identifiers to the whole sorted list
      // of all local identifiers for all functions.
      List<LocalPlaceholder> currentSortedPlaceholders =
          sorted(functionScope.localPlaceholders,
              compareBy((LocalPlaceholder ph) => -ph.nodes.length));
      List<Set<Node>> currentSortedNodes =
          currentSortedPlaceholders.map((ph) => ph.nodes).toList();
      // Make room in all sorted locals list for new stuff.
      while (currentSortedNodes.length > allSortedLocals.length) {
        allSortedLocals.add(new Set<Node>());
      }
      for (int i = 0; i < currentSortedNodes.length; i++) {
        allSortedLocals[i].addAll(currentSortedNodes[i]);
      }
    }

    // Rename elements, members and locals together based on their usage count,
    // otherwise when we rename elements first there will be no good identifiers
    // left for members even if they are used often.
    String elementRenamer(ElementRenamable elementRenamable) =>
        renameElement(elementRenamable.element);
    String memberRenamer(MemberRenamable memberRenamable) =>
        generator.generate(forbiddenIdentifiers.contains);
    String localRenamer(LocalRenamable localRenamable) =>
        generator.generate((name) =>
            allParameterIdentifiers.contains(name)
            || forbiddenIdentifiers.contains(name));
    List<Renamable> renamables = [];
    placeholderCollector.elementNodes.forEach(
        (Element element, Set<Node> nodes) {
      renamables.add(new ElementRenamable(element, nodes, elementRenamer));
    });
    placeholderCollector.memberPlaceholders.forEach(
        (String memberName, Set<Identifier> identifiers) {
      renamables.add(
          new MemberRenamable(memberName, identifiers, memberRenamer));
    });
    for (Set<Node> localIdentifiers in allSortedLocals) {
      renamables.add(new LocalRenamable(localIdentifiers, localRenamer));
    }
    renamables.sort((Renamable renamable1, Renamable renamable2) =>
        renamable1.compareTo(renamable2));
    for (Renamable renamable in renamables) {
      String newName = renamable.rename();
      renameNodes(renamable.nodes, (_) => newName);
    }
  } else {
    // Never rename anything to 'main'.
    final usedTopLevelOrMemberIdentifiers = new Set<String>();
    usedTopLevelOrMemberIdentifiers.add('main');
    usedTopLevelOrMemberIdentifiers.addAll(fixedMemberNames);
    generateUniqueName = (originalName) {
      String newName = conservativeGenerator(
          originalName, usedTopLevelOrMemberIdentifiers.contains);
      usedTopLevelOrMemberIdentifiers.add(newName);
      return newName;
    };
    rename = makeRenamer(generateUniqueName);
    renameElement = makeElementRenamer(rename, generateUniqueName);
    // Rename elements.
    sortedForEach(placeholderCollector.elementNodes,
        (Element element, Set<Node> nodes) {
      renameNodes(nodes, (_) => renameElement(element));
    });

    // Rename locals.
    sortedForEach(placeholderCollector.functionScopes,
        (functionElement, functionScope) {
      Set<LocalPlaceholder> placeholders = functionScope.localPlaceholders;
      Set<String> memberIdentifiers = new Set<String>();
      if (functionElement.getEnclosingClass() != null) {
        functionElement.getEnclosingClass().forEachMember(
            (enclosingClass, member) {
              memberIdentifiers.add(member.name.slowToString());
            });
      }
      Set<String> usedLocalIdentifiers = new Set<String>();
      for (LocalPlaceholder placeholder in placeholders) {
        String nextId =
            conservativeGenerator(placeholder.identifier, (name) =>
                functionScope.parameterIdentifiers.contains(name)
                || usedTopLevelOrMemberIdentifiers.contains(name)
                || usedLocalIdentifiers.contains(name)
                || memberIdentifiers.contains(name));
        usedLocalIdentifiers.add(nextId);
        renameNodes(placeholder.nodes, (_) => nextId);
      }
    });

    final usedMemberIdentifiers = new Set<String>.from(fixedMemberNames);
    // Do not rename members to top-levels, that allows to avoid renaming
    // members to constructors.
    usedMemberIdentifiers.addAll(usedTopLevelOrMemberIdentifiers);
    placeholderCollector.memberPlaceholders.forEach((identifier, nodes) {
      String newIdentifier = conservativeGenerator(
          identifier, usedMemberIdentifiers.contains);
      renameNodes(nodes, (_) => newIdentifier);
    });
  }

  // Rename constructors.
  sortedForEach(placeholderCollector.constructorPlaceholders,
      (Element constructor, List<ConstructorPlaceholder> placeholders) {
        for (ConstructorPlaceholder ph in placeholders) {
          renames[ph.node] =
              renameConstructor(constructor, ph, rename, renameElement);
        }
  });
  sortedForEach(placeholderCollector.privateNodes, (library, nodes) {
    renameNodes(nodes, (node) => rename(library, node.source.slowToString()));
  });
  renameNodes(placeholderCollector.unresolvedNodes,
      (_) => generateUniqueName('Unresolved'));
  renameNodes(placeholderCollector.nullNodes, (_) => '');
  if (cutDeclarationTypes) {
    for (DeclarationTypePlaceholder placeholder in
         placeholderCollector.declarationTypePlaceholders) {
      renames[placeholder.typeNode] = placeholder.requiresVar ? 'var' : '';
    }
  }
}

/** Always tries to return original identifier name unless it is forbidden. */
String conservativeGenerator(
    String originalName, bool isForbidden(String name)) {
  String newName = originalName;
  while (isForbidden(newName)) {
    newName = 'p_$newName';
  }
  return newName;
}

/** Always tries to generate the most compact identifier. */
class MinifyingGenerator {
  static const String firstCharAlphabet =
      r'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
  static const String otherCharsAlphabet =
      r'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_$';
  int nextIdIndex;

  MinifyingGenerator() : nextIdIndex = 0;

  String generate(bool isForbidden(String name)) {
    String newName;
    do {
      newName = getNextId();
    } while(isForbidden(newName));
    return newName;
  }

  /**
   * Generates next mini ID with current index and alphabet.
   * Advances current index.
   * In other words, it converts index to visual representation
   * as if digits are given characters.
   */
  String getNextId() {
    // It's like converting index in decimal to [chars] radix.
    int index = nextIdIndex++;
    StringBuffer resultBuilder = new StringBuffer();
    if (index < firstCharAlphabet.length) return firstCharAlphabet[index];
    resultBuilder.add(firstCharAlphabet[index % firstCharAlphabet.length]);
    index ~/= firstCharAlphabet.length;
    int length = otherCharsAlphabet.length;
    while (index >= length) {
      resultBuilder.add(otherCharsAlphabet[index % length]);
      index ~/= length;
    }
    resultBuilder.add(otherCharsAlphabet[index]);
    return resultBuilder.toString();
  }
}
