// 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.

/// Records accesses to Dart program declarations and generates code that will
/// allow to do the same accesses at runtime using `package:smoke/static.dart`.
/// Internally, this library relies on the `analyzer` to extract data from the
/// program, and then uses [SmokeCodeGenerator] to produce the code needed by
/// the smoke system.
///
/// This library only uses the analyzer to consume data previously produced by
/// running the resolver. This library does not provide any hooks to integrate
/// running the analyzer itself. See `package:code_transformers` to integrate
/// the analyzer into pub transformers.
library smoke.codegen.recorder;

import 'package:analyzer/src/generated/element.dart';
import 'package:analyzer/src/generated/ast.dart';
import 'generator.dart';

typedef String ImportUrlResolver(LibraryElement lib);

/// A recorder that tracks how elements are accessed in order to generate code
/// that replicates those accesses with the smoke runtime.
class Recorder {
  /// Underlying code generator.
  SmokeCodeGenerator generator;

  /// Function that provides the import url for a library element. This may
  /// internally use the resolver to resolve the import url.
  ImportUrlResolver importUrlFor;

  Recorder(this.generator, this.importUrlFor);

  /// Stores mixins that have been recorded and associates a type identifier
  /// with them. Mixins don't have an associated identifier in the code, so we
  /// generate a unique identifier for them and use it throughout the code.
  Map<TypeIdentifier, Map<ClassElement, TypeIdentifier>> _mixins = {};

  /// Adds the superclass information of [type] (including intermediate mixins).
  /// This will not generate data for direct subtypes of Object, as that is
  /// considered redundant information.
  void lookupParent(ClassElement type) {
    var parent = type.supertype;
    var mixins = type.mixins;
    if (parent == null && mixins.isEmpty) return; // type is Object
    var baseType = parent.element;
    var baseId = _typeFor(baseType);
    if (mixins.isNotEmpty) {
      _mixins.putIfAbsent(baseId, () => {});
      for (var m in mixins) {
        var mixinType = m.element;
        var mixinId = _mixins[baseId].putIfAbsent(mixinType, () {
          var comment = '${baseId.name} & ${mixinType.name}';
          return generator.createMixinType(comment);
        });
        if (!baseType.type.isObject) generator.addParent(mixinId, baseId);
        baseType = mixinType;
        baseId = mixinId;
        _mixins.putIfAbsent(mixinId, () => {});
      }
    }
    if (!baseType.type.isObject) generator.addParent(_typeFor(type), baseId);
  }

  TypeIdentifier _typeFor(Element type) => new TypeIdentifier(
      type.library == null ? 'dart:core' : importUrlFor(type.library),
      type.displayName);

  /// Adds any declaration and superclass information that is needed to answer a
  /// query on [type] that matches [options]. Also adds symbols, getters, and
  /// setters if [includeAccessors] is true.
  void runQuery(ClassElement type, QueryOptions options,
      {bool includeAccessors: true}) {
    if (type.type.isObject) return; // We don't include Object in query results.
    var id = _typeFor(type);
    var parent = type.supertype != null ? type.supertype.element : null;
    if (options.includeInherited && parent != null &&
        parent != options.includeUpTo) {
      lookupParent(type);
      runQuery(parent, options, includeAccessors: includeAccessors);
      var parentId = _typeFor(parent);
      for (var m in type.mixins) {
        var mixinClass = m.element;
        var mixinId = _mixins[parentId][mixinClass];
        _runQueryInternal(mixinClass, mixinId, options, includeAccessors);
        parentId = mixinId;
      }
    }
    _runQueryInternal(type, id, options, includeAccessors);
  }

  /// Helper for [runQuery]. This runs the query only on a specific [type],
  /// which could be a class or a mixin labeled by [id].
  // TODO(sigmund): currently we materialize mixins in smoke/static.dart,
  // we should consider to include the mixin declaration information directly,
  // and remove the duplication we have for mixins today.
  void _runQueryInternal(ClassElement type, TypeIdentifier id,
      QueryOptions options, bool includeAccessors) {

    skipBecauseOfAnnotations(Element e) {
      if (options.withAnnotations == null) return false;
      return !_matchesAnnotation(e.metadata, options.withAnnotations);
    }

    if (options.includeFields) {
      for (var f in type.fields) {
        if (f.isStatic) continue;
        if (f.isSynthetic) continue; // exclude getters
        if (options.excludeFinal && f.isFinal) continue;
        var name = f.displayName;
        if (options.matches != null && !options.matches(name)) continue;
        if (skipBecauseOfAnnotations(f)) continue;
        generator.addDeclaration(id, name, _typeFor(f.type.element),
            isField: true, isFinal: f.isFinal,
            annotations: _copyAnnotations(f));
        if (includeAccessors) _addAccessors(name, !f.isFinal);
      }
    }

    if (options.includeProperties) {
      for (var a in type.accessors) {
        if (a is! PropertyAccessorElement) continue;
        if (a.isStatic || !a.isGetter) continue;
        var v = a.variable;
        if (v is FieldElement && !v.isSynthetic) continue; // exclude fields
        if (options.excludeFinal && v.isFinal) continue;
        var name = v.displayName;
        if (options.matches != null && !options.matches(name)) continue;
        if (skipBecauseOfAnnotations(a)) continue;
        generator.addDeclaration(id, name, _typeFor(a.type.returnType.element),
            isProperty: true, isFinal: v.isFinal,
            annotations: _copyAnnotations(a));
        if (includeAccessors) _addAccessors(name, !v.isFinal);
      }
    }

    if (options.includeMethods) {
      for (var m in type.methods) {
        if (m.isStatic) continue;
        var name = m.displayName;
        if (options.matches != null && !options.matches(name)) continue;
        if (skipBecauseOfAnnotations(m)) continue;
        generator.addDeclaration(id, name,
            new TypeIdentifier('dart:core', 'Function'), isMethod: true,
            annotations: _copyAnnotations(m));
        if (includeAccessors) _addAccessors(name, false);
      }
    }
  }

  /// Adds the declaration of [name] if it was found in [type]. If [recursive]
  /// is true, then we continue looking up [name] in the parent classes until we
  /// find it or we reach [includeUpTo] or Object. Returns whether the
  /// declaration was found.  When a declaration is found, add also a symbol,
  /// getter, and setter if [includeAccessors] is true.
  bool lookupMember(ClassElement type, String name, {bool recursive: false,
      bool includeAccessors: true, ClassElement includeUpTo}) =>
    _lookupMemberInternal(type, _typeFor(type), name, recursive,
        includeAccessors, includeUpTo);

  /// Helper for [lookupMember] that walks up the type hierarchy including mixin
  /// classes.
  bool _lookupMemberInternal(ClassElement type, TypeIdentifier id, String name,
      bool recursive, bool includeAccessors, ClassElement includeUpTo) {
    // Exclude members from [Object].
    if (type.type.isObject) return false;
    generator.addEmptyDeclaration(id);
    for (var f in type.fields) {
      if (f.displayName != name) continue;
      if (f.isSynthetic) continue; // exclude getters
      generator.addDeclaration(id, name,
          _typeFor(f.type.element), isField: true, isFinal: f.isFinal,
          isStatic: f.isStatic, annotations: _copyAnnotations(f));
      if (includeAccessors && !f.isStatic) _addAccessors(name, !f.isFinal);
      return true;
    }

    for (var a in type.accessors) {
      if (a is! PropertyAccessorElement) continue;
      // TODO(sigmund): support setters without getters.
      if (!a.isGetter) continue;
      if (a.displayName != name) continue;
      var v = a.variable;
      if (v is FieldElement && !v.isSynthetic) continue; // exclude fields
      generator.addDeclaration(id, name,
          _typeFor(a.type.returnType.element), isProperty: true,
          isFinal: v.isFinal, isStatic: a.isStatic,
          annotations: _copyAnnotations(a));
      if (includeAccessors && !v.isStatic) _addAccessors(name, !v.isFinal);
      return true;
    }

    for (var m in type.methods) {
      if (m.displayName != name) continue;
      generator.addDeclaration(id, name,
          new TypeIdentifier('dart:core', 'Function'), isMethod: true,
          isStatic: m.isStatic, annotations: _copyAnnotations(m));
      if (includeAccessors) {
        if (m.isStatic) {
          generator.addStaticMethod(id, name);
          generator.addSymbol(name);
        } else {
          _addAccessors(name, false);
        }
      }
      return true;
    }

    if (recursive) {
      lookupParent(type);
      var parent = type.supertype != null ? type.supertype.element : null;
      if (parent == null || parent == includeUpTo) return false;
      var parentId = _typeFor(parent);
      for (var m in type.mixins) {
        var mixinClass = m.element;
        var mixinId = _mixins[parentId][mixinClass];
        if (_lookupMemberInternal(mixinClass, mixinId, name, false,
              includeAccessors, includeUpTo)) {
          return true;
        }
        parentId = mixinId;
      }
      return _lookupMemberInternal(parent, parentId, name, true,
          includeAccessors, includeUpTo);
    }
    return false;
  }

  /// Add information so smoke can invoke the static method [type].[name].
  void addStaticMethod(ClassElement type, String name) {
    generator.addStaticMethod(_typeFor(type), name);
  }

  /// Adds [name] as a symbol, a getter, and optionally a setter in [generator].
  _addAccessors(String name, bool includeSetter) {
    generator.addSymbol(name);
    generator.addGetter(name);
    if (includeSetter) generator.addSetter(name);
  }

  /// Copy metadata associated with the declaration of [target].
  List<ConstExpression> _copyAnnotations(Element target) {
    var node = target.node;
    // [node] is the initialization expression, we walk up to get to the actual
    // member declaration where the metadata is attached to.
    while (node is! ClassMember) node = node.parent;
    return node.metadata.map(_convertAnnotation).toList();
  }

  /// Converts annotations into [ConstExpression]s supported by the codegen
  /// library.
  ConstExpression _convertAnnotation(Annotation annotation) {
    var element = annotation.element;
    if (element is ConstructorElement) {
      if (!element.name.isEmpty) {
        throw new UnimplementedError(
            'named constructors are not implemented in smoke.codegen.recorder');
      }

      var positionalArgs = [];
      for (var arg in annotation.arguments.arguments) {
        if (arg is NamedExpression) {
          throw new UnimplementedError(
              'named arguments in constructors are not implemented in '
              'smoke.codegen.recorder');
        }
        positionalArgs.add(_convertExpression(arg));
      }

      return new ConstructorExpression(importUrlFor(element.library),
          element.enclosingElement.name, positionalArgs, const {});
    }

    if (element is PropertyAccessorElement) {
      return new TopLevelIdentifier(
          importUrlFor(element.library), element.name);
    }

    throw new UnsupportedError('unsupported annotation $annotation');
  }

  /// Converts [expression] into a [ConstExpression].
  ConstExpression _convertExpression(Expression expression) {
    if (expression is StringLiteral) {
      return new ConstExpression.string(expression.stringValue);
    }

    if (expression is BooleanLiteral || expression is DoubleLiteral ||
        expression is IntegerLiteral || expression is NullLiteral) {
      return new CodeAsConstExpression("${(expression as dynamic).value}");
    }

    if (expression is Identifier) {
      var element = expression.bestElement;
      if (element == null || !element.isPublic) {
        throw new UnsupportedError('private constants are not supported');
      }

      var url = importUrlFor(element.library);
      if (element is ClassElement) {
        return new TopLevelIdentifier(url, element.name);
      }

      if (element is PropertyAccessorElement) {
        var variable = element.variable;
        if (variable is FieldElement) {
          var cls = variable.enclosingElement;
          return new TopLevelIdentifier(url, '${cls.name}.${variable.name}');
        } else if (variable is TopLevelVariableElement) {
          return new TopLevelIdentifier(url, variable.name);
        }
      }
    }

    throw new UnimplementedError('expression convertion not implemented in '
        'smoke.codegen.recorder (${expression.runtimeType} $expression)');
  }
}

/// Returns whether [metadata] contains any annotation that is either equal to
/// an annotation in [queryAnnotations] or whose type is a subclass of a type
/// listed in [queryAnnotations]. This is equivalent to the check done in
/// `src/common.dart#matchesAnnotation`, except that this is applied to
/// static metadata as it was provided by the analyzer.
bool _matchesAnnotation(Iterable<ElementAnnotation> metadata,
    Iterable<Element> queryAnnotations) {
  for (var meta in metadata) {
    var element = meta.element;
    var exp;
    var type;
    if (element is PropertyAccessorElement) {
      exp = element.variable;
      type = exp.evaluationResult.value.type;
    } else if (element is ConstructorElement) {
      exp = element;
      type = element.enclosingElement.type;
    } else {
      throw new UnimplementedError('Unsupported annotation: ${meta}');
    }
    for (var queryMeta in queryAnnotations) {
      if (exp == queryMeta) return true;
      if (queryMeta is ClassElement && type.isSubtypeOf(queryMeta.type)) {
        return true;
      }
    }
  }
  return false;
}

/// Options equivalent to `smoke.dart#QueryOptions`, except that type
/// information and annotations are denoted by resolver's elements.
class QueryOptions {
  /// Whether to include fields (default is true).
  final bool includeFields;

  /// Whether to include getters and setters (default is true). Note that to
  /// include fields you also need to enable [includeFields].
  final bool includeProperties;

  /// Whether to include symbols from the given type and its superclasses
  /// (except [Object]).
  final bool includeInherited;

  /// If [includeInherited], walk up the type hierarchy up to this type
  /// (defaults to [Object]).
  final ClassElement includeUpTo;

  /// Whether to include final fields and getter-only properties.
  final bool excludeFinal;

  /// Whether to include methods (default is false).
  final bool includeMethods;

  /// If [withAnnotation] is not null, then it should be a list of types, so
  /// only symbols that are annotated with instances of those types are
  /// included.
  final List<Element> withAnnotations;

  /// If [matches] is not null, then only those fields, properties, or methods
  /// that match will be included.
  final NameMatcher matches;

  const QueryOptions({
      this.includeFields: true,
      this.includeProperties: true,
      this.includeInherited: true,
      this.includeUpTo: null,
      this.excludeFinal: false,
      this.includeMethods: false,
      this.withAnnotations: null,
      this.matches: null});
}

/// Predicate that tells whether [name] should be included in query results.
typedef bool NameMatcher(String name);
