// Copyright (c) 2018, 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.

import 'dart:typed_data';

import 'package:analyzer/src/generated/utilities_general.dart';
import 'package:convert/convert.dart';

/// The reference to a class member.
class ClassMemberReference {
  /// The target class name.
  ///
  /// This is different from the class that actually turned out to define
  /// the referenced member at the time of recording this reference. So, we
  /// will notice added overrides in the target class, or anywhere in between.
  final DependencyName target;

  /// Whether the explicit `super` was used as the target.
  /// The [target] is the enclosing class.
  final bool targetSuper;

  /// The name referenced in the [target].
  final String name;

  @override
  final int hashCode;

  ClassMemberReference(this.target, this.targetSuper, this.name)
      : hashCode = JenkinsSmiHash.hash2(target.hashCode, name.hashCode);

  @override
  bool operator ==(other) {
    return other is ClassMemberReference &&
        other.target == target &&
        other.targetSuper == targetSuper &&
        other.name == name;
  }

  @override
  String toString() {
    return '($target, $name, super: $targetSuper)';
  }

  static int compare(ClassMemberReference first, ClassMemberReference second) {
    var result = DependencyName.compare(first.target, second.target);
    if (result != 0) return result;

    if (first.targetSuper && !second.targetSuper) return -1;
    if (!first.targetSuper && second.targetSuper) return 1;

    return first.name.compareTo(second.name);
  }
}

/// A name qualified by a library URI.
class DependencyName {
  /// The URI of the defining library.
  /// Not `null`.
  final Uri libraryUri;

  /// The name of this name object.
  /// If the name starts with `_`, then the name is private.
  /// Names of setters end with `=`.
  final String name;

  /// Whether this name is private, and its [name] starts with `_`.
  final bool isPrivate;

  /// The cached, pre-computed hash code.
  @override
  final int hashCode;

  factory DependencyName(Uri libraryUri, String name) {
    var isPrivate = name.startsWith('_');
    var hashCode = JenkinsSmiHash.hash2(libraryUri.hashCode, name.hashCode);
    return DependencyName._internal(libraryUri, name, isPrivate, hashCode);
  }

  DependencyName._internal(
      this.libraryUri, this.name, this.isPrivate, this.hashCode);

  @override
  bool operator ==(Object other) {
    return other is DependencyName &&
        other.hashCode == hashCode &&
        name == other.name &&
        libraryUri == other.libraryUri;
  }

  /// Whether this name us accessible for the library with the given
  /// [libraryUri], i.e. when the name is public, or is defined in a library
  /// with the same URI.
  bool isAccessibleFor(Uri libraryUri) {
    return !isPrivate || this.libraryUri == libraryUri;
  }

  @override
  String toString() => '$libraryUri::$name';

  /// Compare given names by their raw names.
  ///
  /// This method should be used only for sorting, it does not follow the
  /// complete semantics of [==] and [hashCode].
  static int compare(DependencyName first, DependencyName second) {
    return first.name.compareTo(second.name);
  }
}

/// A dependency node - anything that has a name, and can be referenced.
class DependencyNode {
  /// The API or implementation signature used in [DependencyNodeDependencies]
  /// as a marker that this node is changed, explicitly because its token
  /// signature changed, or implicitly - because it references a changed node.
  static final changedSignature = Uint8List.fromList([0xDE, 0xAD, 0xBE, 0xEF]);

  final DependencyName name;
  final DependencyNodeKind kind;

  /// Dependencies that affect the API of the node, so affect API or
  /// implementation dependencies of the nodes that use this node.
  final DependencyNodeDependencies api;

  /// Additional (to the [api]) dependencies that affect only the
  /// "implementation" of the node, e.g. the body of a method, but are not
  /// visible outside of the node, and so don't affect any other nodes.
  final DependencyNodeDependencies impl;

  /// If the node is a class member, the node of the enclosing class.
  /// Otherwise `null`.
  final DependencyNode enclosingClass;

  /// If the node is a class, the nodes of its type parameters.
  /// Otherwise `null`.
  final List<DependencyNode> classTypeParameters;

  /// If the node is a class, the sorted list of members in this class.
  /// Otherwise `null`.
  List<DependencyNode> classMembers;

  DependencyNode(
    this.name,
    this.kind,
    this.api,
    this.impl, {
    this.enclosingClass,
    this.classTypeParameters,
  });

  /// Return the node that can be referenced by the given [name] from the
  /// library with the given [libraryUri].
  DependencyNode getClassMember(Uri libraryUri, String name) {
    // TODO(scheglov) The list is sorted, use this fact to search faster.
    // TODO(scheglov) Collect superclass members here or outside.
    for (var i = 0; i < classMembers.length; ++i) {
      var member = classMembers[i];
      var memberName = member.name;
      if (memberName.name == name && memberName.isAccessibleFor(libraryUri)) {
        return member;
      }
    }
    return null;
  }

  /// Set new class members for this class.
  void setClassMembers(List<DependencyNode> newClassMembers) {
    classMembers = newClassMembers;
  }

  @override
  String toString() {
    if (enclosingClass != null) {
      return '$enclosingClass::${name.name}';
    }
    return name.toString();
  }

  /// Compare given nodes by their names.
  static int compare(DependencyNode first, DependencyNode second) {
    return DependencyName.compare(first.name, second.name);
  }
}

/// The dependencies of the API or implementation portion of a node.
class DependencyNodeDependencies {
  static final none = DependencyNodeDependencies([], [], [], [], []);

  /// The token signature of this portion of the node. It depends on all
  /// tokens that might affect the node API or implementation resolution.
  final List<int> tokenSignature;

  /// The names that appear unprefixed in this portion of the node, and are
  /// not defined locally in the node. Locally defined names themselves
  /// depend on some non-local nodes, which will also recorded here.
  ///
  /// This list is sorted.
  final List<String> unprefixedReferencedNames;

  /// The names of import prefixes used to reference names in this node.
  ///
  /// This list is sorted.
  final List<String> importPrefixes;

  /// The names referenced by this node with the import prefix at the
  /// corresponding index in [importPrefixes].
  ///
  /// This list is sorted.
  final List<List<String>> importPrefixedReferencedNames;

  /// The class members referenced in this portion of the node.
  ///
  /// This list is sorted.
  final List<ClassMemberReference> classMemberReferences;

  /// All referenced nodes, computed from [unprefixedReferencedNames],
  /// [importPrefixedReferencedNames], and [classMemberReferences].
  List<DependencyNode> referencedNodes;

  /// The transitive signature of this portion of the node, computed using
  /// the [tokenSignature] of this node, and API signatures of the
  /// [referencedNodes].
  List<int> transitiveSignature;

  DependencyNodeDependencies(
      this.tokenSignature,
      this.unprefixedReferencedNames,
      this.importPrefixes,
      this.importPrefixedReferencedNames,
      this.classMemberReferences);

  String get tokenSignatureHex => hex.encode(tokenSignature);
}

/// Kinds of nodes.
enum DependencyNodeKind {
  CLASS,
  CLASS_TYPE_ALIAS,
  CONSTRUCTOR,
  ENUM,
  FUNCTION,
  FUNCTION_TYPE_ALIAS,
  GENERIC_TYPE_ALIAS,
  GETTER,
  METHOD,
  MIXIN,
  SETTER,
  TYPE_PARAMETER,
}
