// 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(
        const SourceString('dynamicFunction'));
    return backend.namer.isolateAccess(element);
  }

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

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

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

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

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

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

  String get defineNativeMethodsName {
    Element element = compiler.findHelper(
        const SourceString('defineNativeMethods'));
    return backend.namer.isolateAccess(element);
  }

  String get defineNativeMethodsNonleafName {
    Element element = compiler.findHelper(
        const SourceString('defineNativeMethodsNonleaf'));
    return backend.namer.isolateAccess(element);
  }

  String get defineNativeMethodsExtendedName {
    Element element = compiler.findHelper(
        const SourceString('defineNativeMethodsExtended'));
    return backend.namer.isolateAccess(element);
  }

  String get defineNativeMethodsFinishName {
    Element element = compiler.findHelper(
        const SourceString('defineNativeMethodsFinish'));
    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.slowToString();
    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.
   */
  void generateNativeClasses(List<ClassElement> classes,
                             CodeBuffer mainBuffer) {
    // 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);
      }
    }

    // Emit code to set up dispatch data that maps tags to the interceptors, but
    // only if native classes are actually instantiated.
    if (compiler.enqueuer.codegen.nativeEnqueuer
        .hasInstantiatedNativeClasses()) {
      void generateDefines(ClassElement classElement) {
        generateDefineNativeMethods(leafTags[classElement],
            null,
            classElement, defineNativeMethodsName);
        List<ClassElement> extensions = extensionPoints[classElement];
        if (extensions == null) {
          generateDefineNativeMethods(nonleafTags[classElement],
              null,
              classElement, defineNativeMethodsNonleafName);
        } else {
          generateDefineNativeMethods(nonleafTags[classElement],
              makeSubclassList(extensions),
              classElement, defineNativeMethodsExtendedName);
        }
      }
      generateDefines(backend.jsInterceptorClass);
      for (ClassElement classElement in classes) {
        generateDefines(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.bufferForElement(classElement, mainBuffer));
        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 generateDefineNativeMethods(
      Set<String> tags, jsAst.Expression extraArgument,
      ClassElement classElement, String definer) {
    if (tags == null) return;
    String tagsString = (tags.toList()..sort()).join('|');

    List arguments = [
        js.string(tagsString),
        js(backend.namer.isolateAccess(classElement))];
    if (extraArgument != null) {
      arguments.add(extraArgument);
    }
    jsAst.Expression definition = js(definer)(arguments);

    nativeBuffer.add(jsAst.prettyPrint(definition, compiler));
    nativeBuffer.add('$N$n');
  }

  jsAst.Expression makeSubclassList(List<ClassElement> classes) {
    return new jsAst.ArrayInitializer.from(
        classes.map((ClassElement classElement) =>
            js(backend.namer.isolateAccess(classElement))));
  }

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

    // jsAst.Expression call = js(defineNativeMethodsFinishName)([]);
    // nativeBuffer.add(jsAst.prettyPrint(call, compiler));
    // nativeBuffer.add('$N$n');
  }

  void potentiallyConvertDartClosuresToJs(
      List<jsAst.Statement> statements,
      FunctionElement member,
      List<jsAst.Parameter> stubParameters) {
    FunctionSignature parameters = member.computeSignature(compiler);
    Element converter =
        compiler.findHelper(const SourceString('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.slowToString();
      // 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');
  }
}
