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

/**
 * Handles construction of TypeVariable constants needed at runtime.
 */
class TypeVariableHandler {
  JavaScriptBackend backend;
  FunctionElement typeVariableConstructor;
  CompileTimeConstantEvaluator evaluator;

  /**
   * Contains all instantiated classes that have type variables and are needed
   * for reflection.
   */
  List<ClassElement> typeVariableClasses = new List<ClassElement>();

  /**
   *  Maps a class element to a list with indices that point to type variables
   *  constants for each of the class' type variables.
   */
  Map<ClassElement, List<int>> typeVariables =
      new Map<ClassElement, List<int>>();

  /**
   *  Maps a TypeVariableType to the index pointing to the constant representing
   *  the corresponding type variable at runtime.
   */
  Map<TypeVariableElement, int> typeVariableConstants =
      new Map<TypeVariableElement, int>();

  TypeVariableHandler(this.backend);

  ClassElement get typeVariableClass => backend.typeVariableClass;
  CodeEmitterTask get task => backend.emitter;
  MetadataEmitter get emitter => task.oldEmitter.metadataEmitter;
  Compiler get compiler => backend.compiler;

  void registerClassWithTypeVariables(ClassElement cls) {
    if (typeVariableClasses != null) {
      typeVariableClasses.add(cls);
    }
  }

  void processTypeVariablesOf(ClassElement cls) {
    //TODO(zarah): Running through all the members is suboptimal. Change this
    // as part of marking elements for reflection.
    bool hasMemberNeededForReflection(ClassElement cls) {
      bool result = false;
      cls.implementation.forEachMember((ClassElement cls, Element member) {
        result = result || backend.referencedFromMirrorSystem(member);
      });
      return result;
    }

    if (!backend.referencedFromMirrorSystem(cls) &&
        !hasMemberNeededForReflection(cls)) {
      return;
    }

    InterfaceType typeVariableType = typeVariableClass.thisType;
    List<int> constants = <int>[];

    for (TypeVariableType currentTypeVariable in cls.typeVariables) {
      TypeVariableElement typeVariableElement = currentTypeVariable.element;

      AstConstant wrapConstant(ConstantExpression constant) {
        return new AstConstant(typeVariableElement,
                                     typeVariableElement.node,
                                     constant);
      }

      ConstantExpression name = new PrimitiveConstantExpression(
          backend.constantSystem.createString(
              new DartString.literal(currentTypeVariable.name)));
      ConstantExpression bound = new PrimitiveConstantExpression(
          backend.constantSystem.createInt(
              emitter.reifyType(typeVariableElement.bound)));
      ConstantExpression type = backend.constants.createTypeConstant(cls);
      List<AstConstant> arguments =
          [wrapConstant(type), wrapConstant(name), wrapConstant(bound)];

      // TODO(johnniwinther): Support a less front-end specific creation of
      // constructed constants.
      AstConstant constant =
          CompileTimeConstantEvaluator.makeConstructedConstant(
              compiler,
              backend.constants,
              typeVariableElement,
              typeVariableElement.node,
              typeVariableType,
              typeVariableConstructor,
              new Selector.callConstructor('', null, 3),
              arguments,
              arguments);
      ConstantValue value = constant.value;
      backend.registerCompileTimeConstant(value, compiler.globalDependencies);
      backend.constants.addCompileTimeConstantForEmission(value);
      constants.add(
          reifyTypeVariableConstant(value, currentTypeVariable.element));
    }
    typeVariables[cls] = constants;
  }

  void onTreeShakingDisabled(Enqueuer enqueuer) {
    if (enqueuer.isResolutionQueue) {
      backend.enqueueClass(
            enqueuer, typeVariableClass, compiler.globalDependencies);
      typeVariableClass.ensureResolved(compiler);
      Link constructors = typeVariableClass.constructors;
      if (constructors.isEmpty && constructors.tail.isEmpty) {
        compiler.internalError(typeVariableClass,
            "Class '$typeVariableClass' should only have one constructor");
      }
      typeVariableConstructor = typeVariableClass.constructors.head;
      backend.enqueueInResolution(typeVariableConstructor,
          compiler.globalDependencies);
      enqueuer.registerInstantiatedType(typeVariableClass.rawType,
          compiler.globalDependencies);
      enqueuer.registerStaticUse(backend.getCreateRuntimeType());
    } else if (typeVariableClasses != null) {
      List<ClassElement> worklist = typeVariableClasses;
      typeVariableClasses = null;
      worklist.forEach((cls) => processTypeVariablesOf(cls));
    }
  }

  /**
   * Adds [c] to [emitter.globalMetadata] and returns the index pointing to
   * the entry.
   *
   * If the corresponding type variable has already been encountered an
   * entry in the list has already been reserved and the constant is added
   * there, otherwise a new entry for [c] is created.
   */
  int reifyTypeVariableConstant(ConstantValue c, TypeVariableElement variable) {
    String name = jsAst.prettyPrint(task.constantReference(c),
                                    compiler).getText();
    int index;
    if (typeVariableConstants.containsKey(variable)) {
      index = typeVariableConstants[variable];
      emitter.globalMetadata[index] = name;
    } else {
      index = emitter.addGlobalMetadata(name);
      typeVariableConstants[variable] = index;
    }
    return index;
  }

  /**
   * Returns the index pointing to the constant in [emitter.globalMetadata]
   * representing this type variable.
   *
   * If the constant has not yet been constructed, an entry is  allocated in
   * the global metadata list and the index pointing to this entry is returned.
   * When the corresponding constant is constructed later,
   * [reifyTypeVariableConstant] will be called and the constant will be added
   * on the allocated entry.
   */
  int reifyTypeVariable(TypeVariableElement variable) {
    if (typeVariableConstants.containsKey(variable)) {
      return typeVariableConstants[variable];
    }

    // TODO(15613): Remove quotes.
    emitter.globalMetadata.add('"Placeholder for ${variable}"');
    return typeVariableConstants[variable] = emitter.globalMetadata.length - 1;
  }

  List<int> typeVariablesOf(ClassElement classElement) {
    List<int> result = typeVariables[classElement];
    if (result == null) {
      result = const <int>[];
    }
    return result;
  }
}
