// 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 js_backend;

class NativeEmitter {

  CodeEmitterTask emitter;
  CodeBuffer nativeBuffer;

  // Native classes found in the application.
  Set<ClassElement> nativeClasses = new Set<ClassElement>();

  // Caches the native subtypes of a native class.
  Map<ClassElement, List<ClassElement>> subtypes;

  // Caches the direct native subtypes of a native class.
  Map<ClassElement, List<ClassElement>> directSubtypes;

  // Caches the methods that have a native body.
  Set<FunctionElement> nativeMethods;

  // Do we need the native emitter to take care of handling
  // noSuchMethod for us? This flag is set to true in the emitter if
  // it finds any native class that needs noSuchMethod handling.
  bool handleNoSuchMethod = false;

  NativeEmitter(this.emitter)
      : subtypes = new Map<ClassElement, List<ClassElement>>(),
        directSubtypes = new Map<ClassElement, List<ClassElement>>(),
        nativeMethods = new Set<FunctionElement>(),
        nativeBuffer = new CodeBuffer();

  Compiler get compiler => emitter.compiler;
  JavaScriptBackend get backend => compiler.backend;

  String get _ => emitter.space;
  String get n => emitter.n;
  String get N => emitter.N;

  String get dynamicName {
    Element element = compiler.findHelper('dynamicFunction');
    return backend.namer.isolateAccess(element);
  }

  String get dynamicFunctionTableName {
    Element element = compiler.findHelper('dynamicFunctionTable');
    return backend.namer.isolateAccess(element);
  }

  String get typeNameOfName {
    Element element = compiler.findHelper('getTypeNameOf');
    return backend.namer.isolateAccess(element);
  }

  String get defPropName {
    Element element = compiler.findHelper('defineProperty');
    return backend.namer.isolateAccess(element);
  }

  String get toStringHelperName {
    Element element = compiler.findHelper('toStringForNativeObject');
    return backend.namer.isolateAccess(element);
  }

  String get hashCodeHelperName {
    Element element = compiler.findHelper('hashCodeForNativeObject');
    return backend.namer.isolateAccess(element);
  }

  String get dispatchPropertyNameVariable {
    Element element = compiler.findInterceptor('dispatchPropertyName');
    return backend.namer.isolateAccess(element);
  }

  // The tags string contains comma-separated 'words' which are either dispatch
  // tags (having JavaScript identifier syntax) and directives that begin with
  // `!`.
  List<String> nativeTagsOfClassRaw(ClassElement cls) {
    String quotedName = cls.nativeTagInfo;
    return quotedName.substring(1, quotedName.length - 1).split(',');
  }

  List<String> nativeTagsOfClass(ClassElement cls) {
    return nativeTagsOfClassRaw(cls).where((s) => !s.startsWith('!')).toList();
  }

  bool nativeHasTagsMarker(ClassElement cls, String marker) {
    return nativeTagsOfClassRaw(cls).contains(marker);
  }

  bool nativeForcedNonLeaf(ClassElement cls) =>
      nativeHasTagsMarker(cls, '!nonleaf');

  /**
   * Writes the class definitions for the interceptors to [mainBuffer].
   * Writes code to associate dispatch tags with interceptors to [nativeBuffer].
   *
   * The interceptors are filtered to avoid emitting trivial interceptors.  For
   * example, if the program contains no code that can distinguish between the
   * numerous subclasses of `Element` then we can pretend that `Element` is a
   * leaf class, and all instances of subclasses of `Element` are instances of
   * `Element`.
   *
   * There is also a performance benefit (in addition to the obvious code size
   * benefit), due to how [getNativeInterceptor] works.  Finding the interceptor
   * of a leaf class in the hierarchy is more efficient that a non-leaf, so it
   * improves performance when more classes can be treated as leaves.
   *
   * [classes] contains native classes, mixin applications, and user subclasses
   * of native classes.  ONLY the native classes are generated here.  [classes]
   * is sorted in desired output order.
   *
   * [additionalProperties] is used to collect properties that are pushed up
   * from the above optimizations onto a non-native class, e.g, `Interceptor`.
   */
  void generateNativeClasses(
      List<ClassElement> classes,
      CodeBuffer mainBuffer,
      Map<ClassElement, Map<String, jsAst.Expression>> additionalProperties) {
    // Compute a pre-order traversal of the subclass forest.  We actually want a
    // post-order traversal but it is easier to compute the pre-order and use it
    // in reverse.

    List<ClassElement> preOrder = <ClassElement>[];
    Set<ClassElement> seen = new Set<ClassElement>();
    seen..add(compiler.objectClass)
        ..add(backend.jsInterceptorClass);
    void walk(ClassElement element) {
      if (seen.contains(element)) return;
      seen.add(element);
      walk(element.superclass);
      preOrder.add(element);
    }
    classes.forEach(walk);

    // Generate code for each native class into [ClassBuilder]s.

    Map<ClassElement, ClassBuilder> builders =
        new Map<ClassElement, ClassBuilder>();
    for (ClassElement classElement in classes) {
      if (classElement.isNative()) {
        ClassBuilder builder = generateNativeClass(classElement);
        builders[classElement] = builder;
      }
    }

    // Find which classes are needed and which are non-leaf classes.  Any class
    // that is not needed can be treated as a leaf class equivalent to some
    // needed class.

    Set<ClassElement> neededClasses = new Set<ClassElement>();
    Set<ClassElement> nonleafClasses = new Set<ClassElement>();

    Map<ClassElement, List<ClassElement>> extensionPoints =
        computeExtensionPoints(preOrder);

    neededClasses.add(compiler.objectClass);

    Set<ClassElement> neededByConstant =
        emitter.interceptorEmitter.interceptorsReferencedFromConstants();
    Set<ClassElement> modifiedClasses =
        emitter.typeTestEmitter.classesModifiedByEmitRuntimeTypeSupport();

    for (ClassElement classElement in preOrder.reversed) {
      // Post-order traversal ensures we visit the subclasses before their
      // superclass.  This makes it easy to tell if a class is needed because a
      // subclass is needed.
      ClassBuilder builder = builders[classElement];
      bool needed = false;
      if (builder == null) {
        // Mixin applications (native+mixin) are non-native, so [classElement]
        // has already been emitted as a regular class.  Mark [classElement] as
        // 'needed' to ensure the native superclass is needed.
        needed = true;
      } else if (!builder.isTrivial) {
        needed = true;
      } else if (neededByConstant.contains(classElement)) {
        needed = true;
      } else if (modifiedClasses.contains(classElement)) {
        // TODO(9556): Remove this test when [emitRuntimeTypeSupport] no longer
        // adds information to a class prototype or constructor.
        needed = true;
      } else if (extensionPoints.containsKey(classElement)) {
        needed = true;
      }
      if (classElement.isNative() && nativeForcedNonLeaf(classElement)) {
        needed = true;
        nonleafClasses.add(classElement);
      }

      if (needed || neededClasses.contains(classElement)) {
        neededClasses.add(classElement);
        neededClasses.add(classElement.superclass);
        nonleafClasses.add(classElement.superclass);
      }
    }

    // Collect all the tags that map to each native class.

    Map<ClassElement, Set<String>> leafTags =
        new Map<ClassElement, Set<String>>();
    Map<ClassElement, Set<String>> nonleafTags =
        new Map<ClassElement, Set<String>>();

    for (ClassElement classElement in classes) {
      if (!classElement.isNative()) continue;
      List<String> nativeTags = nativeTagsOfClass(classElement);

      if (nonleafClasses.contains(classElement) ||
          extensionPoints.containsKey(classElement)) {
        nonleafTags
            .putIfAbsent(classElement, () => new Set<String>())
            .addAll(nativeTags);
      } else {
        ClassElement sufficingInterceptor = classElement;
        while (!neededClasses.contains(sufficingInterceptor)) {
          sufficingInterceptor = sufficingInterceptor.superclass;
        }
        if (sufficingInterceptor == compiler.objectClass) {
          sufficingInterceptor = backend.jsInterceptorClass;
        }
        leafTags
            .putIfAbsent(sufficingInterceptor, () => new Set<String>())
            .addAll(nativeTags);
      }
    }

    // Add properties containing the information needed to construct maps used
    // by getNativeInterceptor and custom elements.
    if (compiler.enqueuer.codegen.nativeEnqueuer
        .hasInstantiatedNativeClasses()) {
      void generateClassInfo(ClassElement classElement) {
        // Property has the form:
        //
        //    "%": "leafTag1|leafTag2|...;nonleafTag1|...;Class1|Class2|...",
        //
        // If there is no data following a semicolon, the semicolon can be
        // omitted.

        String formatTags(Iterable<String> tags) {
          if (tags == null) return '';
          return (tags.toList()..sort()).join('|');
        }

        List<ClassElement> extensions = extensionPoints[classElement];

        String leafStr = formatTags(leafTags[classElement]);
        String nonleafStr = formatTags(nonleafTags[classElement]);

        StringBuffer sb = new StringBuffer(leafStr);
        if (nonleafStr != '') {
          sb..write(';')..write(nonleafStr);
        }
        if (extensions != null) {
          sb..write(';')
            ..writeAll(extensions.map(backend.namer.getNameOfClass), '|');
        }
        String encoding = sb.toString();

        ClassBuilder builder = builders[classElement];
        if (builder == null) {
          // No builder because this is an intermediate mixin application or
          // Interceptor - these are not direct native classes.
          if (encoding != '') {
            Map<String, jsAst.Expression> properties =
                additionalProperties.putIfAbsent(classElement,
                    () => new LinkedHashMap<String, jsAst.Expression>());
            properties[backend.namer.nativeSpecProperty] = js.string(encoding);
          }
        } else {
          builder.addProperty(
              backend.namer.nativeSpecProperty, js.string(encoding));
        }
      }
      generateClassInfo(backend.jsInterceptorClass);
      for (ClassElement classElement in classes) {
        generateClassInfo(classElement);
      }
    }

    // Emit the native class interceptors that were actually used.
    for (ClassElement classElement in classes) {
      if (!classElement.isNative()) continue;
      if (neededClasses.contains(classElement)) {
        // Define interceptor class for [classElement].
        emitter.classEmitter.emitClassBuilderWithReflectionData(
            backend.namer.getNameOfClass(classElement),
            classElement, builders[classElement],
            emitter.getElementDecriptor(classElement));
        emitter.needsDefineClass = true;
      }
    }
  }

  /**
   * Computes the native classes that are extended (subclassed) by non-native
   * classes and the set non-mative classes that extend them.  (A List is used
   * instead of a Set for out stability).
   */
  Map<ClassElement, List<ClassElement>> computeExtensionPoints(
      List<ClassElement> classes) {
    ClassElement nativeSuperclassOf(ClassElement element) {
      if (element == null) return null;
      if (element.isNative()) return element;
      return nativeSuperclassOf(element.superclass);
    }

    ClassElement nativeAncestorOf(ClassElement element) {
      return nativeSuperclassOf(element.superclass);
    }

    Map<ClassElement, List<ClassElement>> map =
        new Map<ClassElement, List<ClassElement>>();

    for (ClassElement classElement in classes) {
      if (classElement.isNative()) continue;
      ClassElement nativeAncestor = nativeAncestorOf(classElement);
      if (nativeAncestor != null) {
        map
          .putIfAbsent(nativeAncestor, () => <ClassElement>[])
          .add(classElement);
      }
    }
    return map;
  }

  ClassBuilder generateNativeClass(ClassElement classElement) {
    // TODO(sra): Issue #13731- this is commented out as part of custom element
    // constructor work.
    //assert(!classElement.hasBackendMembers);
    nativeClasses.add(classElement);

    ClassElement superclass = classElement.superclass;
    assert(superclass != null);
    // Fix superclass.  TODO(sra): make native classes inherit from Interceptor.
    assert(superclass != compiler.objectClass);
    if (superclass == compiler.objectClass) {
      superclass = backend.jsInterceptorClass;
    }

    String superName = backend.namer.getNameOfClass(superclass);

    ClassBuilder builder = new ClassBuilder();
    emitter.classEmitter.emitClassConstructor(classElement, builder, null);
    bool hasFields = emitter.classEmitter.emitFields(
        classElement, builder, superName, classIsNative: true);
    int propertyCount = builder.properties.length;
    emitter.classEmitter.emitClassGettersSetters(classElement, builder);
    emitter.classEmitter.emitInstanceMembers(classElement, builder);
    emitter.typeTestEmitter.emitIsTests(classElement, builder);

    if (!hasFields &&
        builder.properties.length == propertyCount &&
        superclass is! MixinApplicationElement) {
      builder.isTrivial = true;
    }

    return builder;
  }

  void finishGenerateNativeClasses() {
    // TODO(sra): Put specialized version of getNativeMethods on
    // `Object.prototype` to avoid checking in `getInterceptor` and
    // specializations.
  }

  void potentiallyConvertDartClosuresToJs(
      List<jsAst.Statement> statements,
      FunctionElement member,
      List<jsAst.Parameter> stubParameters) {
    FunctionSignature parameters = member.computeSignature(compiler);
    Element converter =
        compiler.findHelper('convertDartClosureToJS');
    String closureConverter = backend.namer.isolateAccess(converter);
    Set<String> stubParameterNames = new Set<String>.from(
        stubParameters.map((param) => param.name));
    parameters.forEachParameter((Element parameter) {
      String name = parameter.name;
      // If [name] is not in [stubParameters], then the parameter is an optional
      // parameter that was not provided for this stub.
      for (jsAst.Parameter stubParameter in stubParameters) {
        if (stubParameter.name == name) {
          DartType type = parameter.computeType(compiler).unalias(compiler);
          if (type is FunctionType) {
            // The parameter type is a function type either directly or through
            // typedef(s).
            FunctionType functionType = type;
            int arity = functionType.computeArity();
            statements.add(
                js('$name = $closureConverter($name, $arity)').toStatement());
            break;
          }
        }
      }
    });
  }

  List<jsAst.Statement> generateParameterStubStatements(
      Element member,
      bool isInterceptedMethod,
      String invocationName,
      List<jsAst.Parameter> stubParameters,
      List<jsAst.Expression> argumentsBuffer,
      int indexOfLastOptionalArgumentInParameters) {
    // The target JS function may check arguments.length so we need to
    // make sure not to pass any unspecified optional arguments to it.
    // For example, for the following Dart method:
    //   foo([x, y, z]);
    // The call:
    //   foo(y: 1)
    // must be turned into a JS call to:
    //   foo(null, y).

    ClassElement classElement = member.enclosingElement;

    List<jsAst.Statement> statements = <jsAst.Statement>[];
    potentiallyConvertDartClosuresToJs(statements, member, stubParameters);

    String target;
    jsAst.Expression receiver;
    List<jsAst.Expression> arguments;

    assert(invariant(member, nativeMethods.contains(member)));
    // When calling a JS method, we call it with the native name, and only the
    // arguments up until the last one provided.
    target = member.fixedBackendName();

    if (isInterceptedMethod) {
      receiver = argumentsBuffer[0];
      arguments = argumentsBuffer.sublist(1,
          indexOfLastOptionalArgumentInParameters + 1);
    } else {
      receiver = js('this');
      arguments = argumentsBuffer.sublist(0,
          indexOfLastOptionalArgumentInParameters + 1);
    }
    statements.add(new jsAst.Return(receiver[target](arguments)));

    return statements;
  }

  bool isSupertypeOfNativeClass(Element element) {
    if (element.isTypeVariable()) {
      compiler.cancel("Is check for type variable", element: element);
      return false;
    }
    if (element.computeType(compiler).unalias(compiler) is FunctionType) {
      // The element type is a function type either directly or through
      // typedef(s).
      return false;
    }

    if (!element.isClass()) {
      compiler.cancel("Is check does not handle element", element: element);
      return false;
    }

    if (backend.classesMixedIntoNativeClasses.contains(element)) return true;

    return subtypes[element] != null;
  }

  bool requiresNativeIsCheck(Element element) {
    // TODO(sra): Remove this function.  It determines if a native type may
    // satisfy a check against [element], in which case an interceptor must be
    // used.  We should also use an interceptor if the check can't be satisfied
    // by a native class in case we get a native instance that tries to spoof
    // the type info.  i.e the criteria for whether or not to use an interceptor
    // is whether the receiver can be native, not the type of the test.
    if (!element.isClass()) return false;
    ClassElement cls = element;
    if (Elements.isNativeOrExtendsNative(cls)) return true;
    return isSupertypeOfNativeClass(element);
  }

  void assembleCode(CodeBuffer targetBuffer) {
    List<jsAst.Property> objectProperties = <jsAst.Property>[];

    void addProperty(String name, jsAst.Expression value) {
      objectProperties.add(new jsAst.Property(js.string(name), value));
    }

    if (!nativeClasses.isEmpty) {
      // If the native emitter has been asked to take care of the
      // noSuchMethod handlers, we do that now.
      if (handleNoSuchMethod) {
        emitter.nsmEmitter.emitNoSuchMethodHandlers(addProperty);
      }
    }

    // If we have any properties to add to Object.prototype, we run
    // through them and add them using defineProperty.
    if (!objectProperties.isEmpty) {
      jsAst.Expression init =
          js.fun(['table'],
              new jsAst.ForIn(
                  new jsAst.VariableDeclarationList(
                      [new jsAst.VariableInitialization(
                          new jsAst.VariableDeclaration('key'),
                          null)]),
                  js('table'),
                  new jsAst.ExpressionStatement(
                      js('$defPropName(Object.prototype, key, table[key])'))))(
              new jsAst.ObjectInitializer(objectProperties));

      if (emitter.compiler.enableMinification) targetBuffer.add(';');
      targetBuffer.add(jsAst.prettyPrint(
          new jsAst.ExpressionStatement(init), compiler));
      targetBuffer.add('\n');
    }

    targetBuffer.add(nativeBuffer);
    targetBuffer.add('\n');
  }
}
