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

// TODO(kasperl): This actually holds getters and setters just fine
// too and stricly they aren't functions. Maybe this needs a better
// name -- something like ElementSet seems a bit too generic.
class FunctionSet {
  final Compiler compiler;
  final Map<String, FunctionSetNode> nodes =
      new Map<String, FunctionSetNode>();
  FunctionSet(this.compiler);

  FunctionSetNode newNode(String name)
      => new FunctionSetNode(name);

  void add(Element element) {
    assert(element.isInstanceMember);
    assert(!element.isAbstract);
    String name = element.name;
    FunctionSetNode node = nodes.putIfAbsent(name, () => newNode(name));
    node.add(element);
  }

  void remove(Element element) {
    assert(element.isInstanceMember);
    assert(!element.isAbstract);
    String name = element.name;
    FunctionSetNode node = nodes[name];
    if (node != null) {
      node.remove(element);
    }
  }

  bool contains(Element element) {
    assert(element.isInstanceMember);
    assert(!element.isAbstract);
    String name = element.name;
    FunctionSetNode node = nodes[name];
    return (node != null)
        ? node.contains(element)
        : false;
  }

  /**
   * Returns an object that allows iterating over all the functions
   * that may be invoked with the given [selector].
   */
  Iterable<Element> filter(Selector selector) {
    return query(selector).functions;
  }

  TypeMask receiverType(Selector selector) {
    return query(selector).computeMask(compiler.world);
  }

  FunctionSetQuery query(Selector selector) {
    String name = selector.name;
    FunctionSetNode node = nodes[name];
    FunctionSetNode noSuchMethods = nodes[Compiler.NO_SUCH_METHOD];
    if (node != null) {
      return node.query(selector, compiler, noSuchMethods);
    }
    // If there is no method that matches [selector] we know we can
    // only hit [:noSuchMethod:].
    if (noSuchMethods == null) return const FunctionSetQuery(const <Element>[]);
    selector = (selector.mask == null)
        ? compiler.noSuchMethodSelector
        : new TypedSelector(selector.mask, compiler.noSuchMethodSelector,
            compiler.world);

    return noSuchMethods.query(selector, compiler, null);
  }

  void forEach(Function action) {
    nodes.forEach((String name, FunctionSetNode node) {
      node.forEach(action);
    });
  }
}


class FunctionSetNode {
  final String name;
  final Map<Selector, FunctionSetQuery> cache =
      new Map<Selector, FunctionSetQuery>();

  // Initially, we keep the elements in a list because it is more
  // compact than a hash set. Once we get enough elements, we change
  // the representation to be a set to get faster contains checks.
  static const int MAX_ELEMENTS_IN_LIST = 8;
  var elements = <Element>[];
  bool isList = true;

  FunctionSetNode(this.name);

  void add(Element element) {
    assert(element.name == name);
    // We try to avoid clearing the cache unless we have to. For that
    // reason we keep the explicit contains check even though the add
    // method ends up doing the work again (for sets).
    if (!elements.contains(element)) {
      if (isList && elements.length >= MAX_ELEMENTS_IN_LIST) {
        elements = elements.toSet();
        isList = false;
      }
      elements.add(element);
      if (!cache.isEmpty) cache.clear();
    }
  }

  void remove(Element element) {
    assert(element.name == name);
    if (isList) {
      List list = elements;
      int index = list.indexOf(element);
      if (index < 0) return;
      Element last = list.removeLast();
      if (index != list.length) {
        list[index] = last;
      }
      if (!cache.isEmpty) cache.clear();
    } else {
      Set set = elements;
      if (set.remove(element)) {
        // To avoid wobbling between the two representations, we do
        // not transition back to the list representation even if we
        // end up with few enough elements at this point.
        if (!cache.isEmpty) cache.clear();
      }
    }
  }

  bool contains(Element element) {
    assert(element.name == name);
    return elements.contains(element);
  }

  void forEach(Function action) {
    elements.forEach(action);
  }

  TypeMask getNonNullTypeMaskOfSelector(Selector selector, Compiler compiler) {
    // TODO(ngeoffray): We should probably change untyped selector
    // to always be a subclass of Object.
    return selector.mask != null
        ? selector.mask
        : new TypeMask.subclass(compiler.objectClass, compiler.world);
    }

  FunctionSetQuery query(Selector selector,
                         Compiler compiler,
                         FunctionSetNode noSuchMethods) {
    ClassWorld classWorld = compiler.world;
    assert(selector.name == name);
    FunctionSetQuery result = cache[selector];
    if (result != null) return result;
    Setlet<Element> functions;
    for (Element element in elements) {
      if (selector.appliesUnnamed(element, classWorld)) {
        if (functions == null) {
          // Defer the allocation of the functions set until we are
          // sure we need it. This allows us to return immutable empty
          // lists when the filtering produced no results.
          functions = new Setlet<Element>();
        }
        functions.add(element);
      }
    }

    TypeMask mask = getNonNullTypeMaskOfSelector(selector, compiler);
    // If we cannot ensure a method will be found at runtime, we also
    // add [noSuchMethod] implementations that apply to [mask] as
    // potential targets.
    if (noSuchMethods != null
        && mask.needsNoSuchMethodHandling(selector, classWorld)) {
      FunctionSetQuery noSuchMethodQuery = noSuchMethods.query(
          new TypedSelector(
              mask, compiler.noSuchMethodSelector, classWorld),
          compiler,
          null);
      if (!noSuchMethodQuery.functions.isEmpty) {
        if (functions == null) {
          functions = new Setlet<Element>.from(noSuchMethodQuery.functions);
        } else {
          functions.addAll(noSuchMethodQuery.functions);
        }
      }
    }
    cache[selector] = result = (functions != null)
        ? newQuery(functions, selector, compiler)
        : const FunctionSetQuery(const <Element>[]);
    return result;
  }

  FunctionSetQuery newQuery(Iterable<Element> functions,
                            Selector selector,
                            Compiler compiler) {
    return new FullFunctionSetQuery(functions);
  }
}

class FunctionSetQuery {
  final Iterable<Element> functions;
  TypeMask computeMask(ClassWorld classWorld) => const TypeMask.nonNullEmpty();
  const FunctionSetQuery(this.functions);
}

class FullFunctionSetQuery extends FunctionSetQuery {
  TypeMask _mask;

  /**
   * Compute the type of all potential receivers of this function set.
   */
  TypeMask computeMask(ClassWorld classWorld) {
    assert(classWorld.hasAnySubclass(classWorld.objectClass));
    if (_mask != null) return _mask;
    return _mask = new TypeMask.unionOf(functions
        .expand((element) {
          ClassElement cls = element.enclosingClass;
          return [cls]..addAll(classWorld.mixinUsesOf(cls));
        })
        .map((cls) {
          if (classWorld.backend.isNullImplementation(cls)) {
            return const TypeMask.empty();
          } else {
            return new TypeMask.nonNullSubclass(cls.declaration, classWorld);
          }
        }),
        classWorld);
  }

  FullFunctionSetQuery(functions) : super(functions);
}
