// 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 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}) =>
    _lookupMemberInternal(type, _typeFor(type), name, recursive,
        includeAccessors);

  /// Helper for [lookupMember] that walks up the type hierarchy including mixin
  /// classes.
  bool _lookupMemberInternal(ClassElement type, TypeIdentifier id, String name,
      bool recursive, bool includeAccessors) {
    // 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) 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)) {
          return true;
        }
        parentId = mixinId;
      }
      return _lookupMemberInternal(parent, parentId, name, true,
          includeAccessors);
    }
    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);
