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

library fasta.class_hierarchy_builder;

import 'package:kernel/ast.dart'
    show Library, Member, Name, Procedure, ProcedureKind;

import 'package:kernel/class_hierarchy.dart' show ClassHierarchy;

import '../messages.dart'
    show
        LocatedMessage,
        messageDeclaredMemberConflictsWithInheritedMember,
        messageDeclaredMemberConflictsWithInheritedMemberCause,
        messageInheritedMembersConflict,
        messageInheritedMembersConflictCause1,
        messageInheritedMembersConflictCause2,
        templateMissingImplementationCause,
        templateMissingImplementationNotAbstract;

import '../names.dart' show noSuchMethodName;

import '../scope.dart' show Scope;

import 'kernel_builder.dart'
    show
        Declaration,
        LibraryBuilder,
        KernelClassBuilder,
        KernelNamedTypeBuilder,
        KernelTypeBuilder;

int compareDeclarations(Declaration a, Declaration b) {
  return ClassHierarchy.compareMembers(a.target, b.target);
}

ProcedureKind memberKind(Member member) {
  return member is Procedure ? member.kind : null;
}

bool isNameVisibleIn(
    Name name, LibraryBuilder<KernelTypeBuilder, Library> library) {
  return !name.isPrivate || name.library == library.target;
}

class ClassHierarchyBuilder {
  final Map<KernelClassBuilder, ClassHierarchyNode> nodes =
      <KernelClassBuilder, ClassHierarchyNode>{};

  final KernelClassBuilder objectClass;

  bool hasNoSuchMethod = false;

  int abstractMemberCount = 0;

  ClassHierarchyBuilder(this.objectClass);

  Declaration handleOverride(KernelClassBuilder cls, Declaration member,
      Declaration superMember, bool isMergingInterfaces) {
    if (member.next != null || superMember.next != null) {
      // Don't check overrides involving duplicated members.
      return member;
    }
    Member target = member.target;
    Member superTarget = superMember.target;
    if ((memberKind(target) ?? ProcedureKind.Getter) !=
        (memberKind(superTarget) ?? ProcedureKind.Getter)) {
      String name = member.fullNameForErrors;
      if (isMergingInterfaces) {
        cls.addProblem(messageInheritedMembersConflict, cls.charOffset,
            cls.fullNameForErrors.length,
            context: <LocatedMessage>[
              messageInheritedMembersConflictCause1.withLocation(
                  member.fileUri, member.charOffset, name.length),
              messageInheritedMembersConflictCause2.withLocation(
                  superMember.fileUri, superMember.charOffset, name.length),
            ]);
      } else {
        cls.addProblem(messageDeclaredMemberConflictsWithInheritedMember,
            member.charOffset, name.length,
            context: <LocatedMessage>[
              messageDeclaredMemberConflictsWithInheritedMemberCause
                  .withLocation(
                      superMember.fileUri, superMember.charOffset, name.length)
            ]);
      }
    }
    if (target.name == noSuchMethodName && !target.isAbstract) {
      hasNoSuchMethod = true;
    }
    Declaration result = member;
    if (isMergingInterfaces) {
      // TODO(ahe): Combine the signatures of member and superMember.
    } else if (target.isAbstract) {
      if (!superTarget.isAbstract) {
        // An abstract method doesn't override an implemention inherited from a
        // superclass.
        result = superMember;
      } else {
        abstractMemberCount++;
      }
    }
    return result;
  }

  void handleNewMember(Declaration member, bool isMergingInterfaces) {
    Member target = member.target;
    if (!isMergingInterfaces && target.isAbstract) {
      abstractMemberCount++;
    }
  }

  void handleInheritance(
      KernelClassBuilder cls, Declaration member, bool isMergingInterfaces) {
    Member target = member.target;
    if (!isMergingInterfaces && target.isAbstract) {
      if (isNameVisibleIn(target.name, cls.library)) {
        abstractMemberCount++;
      }
    }
    if (member.parent != objectClass &&
        target.name == noSuchMethodName &&
        !target.isAbstract) {
      hasNoSuchMethod = true;
    }
  }

  void add(KernelClassBuilder cls) {
    if (cls.isPatch) {
      // TODO(ahe): What about patch classes. Have we injected patched members
      // into the class-builder's scope?
      return;
    }
    ClassHierarchyNode supernode;
    if (objectClass != cls) {
      supernode = getNode(cls.supertype);
      if (supernode == null) {
        supernode = nodes[objectClass];
        if (supernode == null) {
          add(objectClass);
          supernode = nodes[objectClass];
        }
      }
      assert(supernode != null);
    }

    Scope scope = cls.scope;
    if (cls.isMixinApplication) {
      Declaration mixin = getDeclaration(cls.mixedInType);
      if (mixin is KernelClassBuilder) {
        scope = mixin.scope;
      }
    }
    List<Declaration> sortedLocals =
        new List<Declaration>.from(scope.local.values)
          ..sort(compareDeclarations);
    List<Declaration> sortedSetters =
        new List<Declaration>.from(scope.setters.values)
          ..sort(compareDeclarations);
    List<Declaration> allMembers;
    List<Declaration> allSetters;
    List<Declaration> interfaceMembers;
    List<Declaration> interfaceSetters;
    if (supernode == null) {
      // This should be Object.
      interfaceMembers = allMembers = sortedLocals;
      interfaceSetters = allSetters = sortedSetters;
    } else {
      allMembers = merge(cls, sortedLocals, supernode.classMembers, false);
      allSetters = merge(cls, sortedSetters, supernode.classSetters, false);
      List<KernelTypeBuilder> interfaces = cls.interfaces;
      if (interfaces != null) {
        MergeResult result = mergeInterfaces(cls, supernode, interfaces);
        interfaceMembers = result.mergedMembers;
        interfaceSetters = result.mergedSetters;
      } else {
        interfaceMembers = allMembers;
        interfaceSetters = allSetters;
      }
    }
    nodes[cls] = new ClassHierarchyNode(
        cls, scope, allMembers, allSetters, interfaceMembers, interfaceSetters);
    mergeAccessors(cls, allMembers, allSetters);

    if (abstractMemberCount != 0 && !cls.isAbstract) {
      if (!hasNoSuchMethod) {
        reportMissingMembers(cls, allMembers, allSetters);
      }
      installNsmHandlers(cls);
    }
    hasNoSuchMethod = false;
    abstractMemberCount = 0;
  }

  MergeResult mergeInterfaces(KernelClassBuilder cls,
      ClassHierarchyNode supernode, List<KernelTypeBuilder> interfaces) {
    List<List<Declaration>> memberLists =
        List<List<Declaration>>(interfaces.length + 1);
    List<List<Declaration>> setterLists =
        List<List<Declaration>>(interfaces.length + 1);
    memberLists[0] = supernode.interfaceMembers;
    setterLists[0] = supernode.interfaceSetters;
    for (int i = 0; i < interfaces.length; i++) {
      ClassHierarchyNode interfaceNode = getNode(interfaces[i]);
      if (interfaceNode == null) {
        memberLists[i + 1] = <Declaration>[];
        setterLists[i + 1] = <Declaration>[];
      } else {
        memberLists[i + 1] = interfaceNode.interfaceMembers;
        setterLists[i + 1] = interfaceNode.interfaceSetters;
      }
    }
    return new MergeResult(
        mergeLists(cls, memberLists), mergeLists(cls, setterLists));
  }

  List<Declaration> mergeLists(
      KernelClassBuilder cls, List<List<Declaration>> input) {
    // This is a k-way merge sort (where k is `interfaces.length + 1`). We
    // merge the lists pairwise, which reduces the number of lists to merge by
    // half on each iteration. Consequently, we perform O(log k) merges.
    while (input.length > 1) {
      List<List<Declaration>> output = <List<Declaration>>[];
      for (int i = 0; i < input.length - 1; i += 2) {
        output.add(merge(cls, input[i], input[i + 1], true));
      }
      if (input.length.isOdd) {
        output.add(input.last);
      }
      input = output;
    }
    return input.single;
  }

  /// Merge [and check] accessors. This entails removing setters corresponding
  /// to fields, and checking that setters don't override regular methods.
  void mergeAccessors(KernelClassBuilder cls, List<Declaration> allMembers,
      List<Declaration> allSetters) {
    List<Declaration> overriddenSetters;
    int i = 0;
    int j = 0;
    while (i < allMembers.length && j < allSetters.length) {
      Declaration member = allMembers[i];
      Declaration setter = allSetters[j];
      final int compare = compareDeclarations(member, setter);
      if (compare == 0) {
        if (member.isField) {
          // TODO(ahe): What happens if we have both a field and a setter
          // declared in the same class?
          if (!member.isFinal && !member.isConst) {
            // The field overrides the setter.
            (overriddenSetters ??= <Declaration>[]).add(setter);
            Member target = setter.target;
            if (target.isAbstract) {
              abstractMemberCount--;
            }
          }
        } else if (!member.isGetter) {
          String name = member.fullNameForErrors;
          cls.library.addProblem(
              messageDeclaredMemberConflictsWithInheritedMember,
              member.charOffset,
              name.length,
              member.fileUri,
              context: <LocatedMessage>[
                messageDeclaredMemberConflictsWithInheritedMemberCause
                    .withLocation(
                        setter.fileUri, setter.charOffset, name.length)
              ]);
        }
        i++;
        j++;
      } else if (compare < 0) {
        i++;
      } else {
        j++;
      }
    }
    // One of of the two lists is now exhausted. What remains in the other list
    // cannot be a conflict.

    if (overriddenSetters != null) {
      // Remove [overriddenSetters] from [allSetters] by copying [allSetters]
      // to itself.
      int i = 0;
      int j = 0;
      int storeIndex = 0;
      while (i < allSetters.length && j < overriddenSetters.length) {
        if (allSetters[i] == overriddenSetters[j]) {
          i++;
          j++;
        } else {
          allSetters[storeIndex++] = allSetters[i++];
        }
      }
      while (i < allSetters.length) {
        allSetters[storeIndex++] = allSetters[i++];
      }
      allSetters.length = storeIndex;
    }
  }

  void reportMissingMembers(KernelClassBuilder cls,
      List<Declaration> allMembers, List<Declaration> allSetters) {
    List<LocatedMessage> context = <LocatedMessage>[];
    List<String> missingNames = <String>[];
    for (int j = 0; j < 2; j++) {
      List<Declaration> members = j == 0 ? allMembers : allSetters;
      for (int i = 0; i < members.length; i++) {
        Declaration declaration = members[i];
        Member target = declaration.target;
        if (target.isAbstract && isNameVisibleIn(target.name, cls.library)) {
          String name = declaration.fullNameForErrors;
          String parentName = declaration.parent.fullNameForErrors;
          String displayName =
              declaration.isSetter ? "$parentName.$name=" : "$parentName.$name";
          missingNames.add(displayName);
          context.add(templateMissingImplementationCause
              .withArguments(displayName)
              .withLocation(
                  declaration.fileUri, declaration.charOffset, name.length));
        }
      }
    }
    cls.addProblem(
        templateMissingImplementationNotAbstract.withArguments(
            cls.fullNameForErrors, missingNames),
        cls.charOffset,
        cls.fullNameForErrors.length,
        context: context);
  }

  void installNsmHandlers(KernelClassBuilder cls) {
    // TOOD(ahe): Implement this.
  }

  ClassHierarchyNode getNode(KernelTypeBuilder type) {
    if (type is KernelNamedTypeBuilder) {
      Declaration declaration = type.declaration;
      if (declaration is KernelClassBuilder) {
        ClassHierarchyNode node = nodes[declaration];
        if (node == null && declaration is KernelClassBuilder) {
          add(declaration);
          node = nodes[declaration];
        }
        return node;
      }
    }
    return null;
  }

  Declaration getDeclaration(KernelTypeBuilder type) {
    return type is KernelNamedTypeBuilder ? type.declaration : null;
  }

  List<Declaration> merge(
      KernelClassBuilder cls,
      List<Declaration> localMembers,
      List<Declaration> superMembers,
      bool isMergingInterfaces) {
    final List<Declaration> mergedMembers = new List<Declaration>.filled(
        localMembers.length + superMembers.length, null,
        growable: true);

    int mergedMemberCount = 0;

    int i = 0;
    int j = 0;
    while (i < localMembers.length && j < superMembers.length) {
      final Declaration localMember = localMembers[i];
      final Declaration superMember = superMembers[j];
      final int compare = compareDeclarations(localMember, superMember);
      if (compare == 0) {
        mergedMembers[mergedMemberCount++] =
            handleOverride(cls, localMember, superMember, isMergingInterfaces);
        i++;
        j++;
      } else if (compare < 0) {
        handleNewMember(localMember, isMergingInterfaces);
        mergedMembers[mergedMemberCount++] = localMember;
        i++;
      } else {
        handleInheritance(cls, superMember, isMergingInterfaces);
        mergedMembers[mergedMemberCount++] = superMember;
        j++;
      }
    }
    while (i < localMembers.length) {
      final Declaration localMember = localMembers[i];
      handleNewMember(localMember, isMergingInterfaces);
      mergedMembers[mergedMemberCount++] = localMember;
      i++;
    }
    while (j < superMembers.length) {
      final Declaration superMember = superMembers[j];
      handleInheritance(cls, superMember, isMergingInterfaces);
      mergedMembers[mergedMemberCount++] = superMember;
      j++;
    }
    return mergedMembers..length = mergedMemberCount;
  }
}

class ClassHierarchyNode {
  /// The class corresponding to this hierarchy node.
  final KernelClassBuilder cls;

  /// The local members of [cls]. For regular classes, this is simply
  /// `cls.scope`, but for mixin-applications this is the mixed-in type's
  /// scope. The members are sorted in order of declaration.
  // TODO(ahe): Do we need to copy the scope from the mixed-in type to remove
  // static members?
  final Scope localMembers;

  /// All the members of this class including [classMembers] of its
  /// superclasses. The members are sorted by [compareDeclarations].
  final List<Declaration> classMembers;

  /// Similar to [classMembers] but for setters.
  final List<Declaration> classSetters;

  /// All the interface members of this class including [interfaceMembers] of
  /// its supertypes. The members are sorted by [compareDeclarations].
  ///
  /// In addition to the members of [classMembers] this also contains members
  /// from interfaces.
  final List<Declaration> interfaceMembers;

  /// Similar to [interfaceMembers] but for setters.
  final List<Declaration> interfaceSetters;

  ClassHierarchyNode(this.cls, this.localMembers, this.classMembers,
      this.classSetters, this.interfaceMembers, this.interfaceSetters);
}

class MergeResult {
  final List<Declaration> mergedMembers;

  final List<Declaration> mergedSetters;

  MergeResult(this.mergedMembers, this.mergedSetters);
}
