// Copyright (c) 2015, 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 dart2js.resolution.tree_elements;

import '../common.dart';
import '../constants/expressions.dart';
import '../dart_types.dart';
import '../diagnostics/source_span.dart';
import '../elements/elements.dart';
import '../tree/tree.dart';
import '../universe/selector.dart' show Selector;
import '../util/util.dart';
import 'secret_tree_element.dart' show getTreeElement, setTreeElement;
import 'send_structure.dart';

abstract class TreeElements {
  AnalyzableElement get analyzedElement;
  Iterable<SourceSpan> get superUses;

  void forEachConstantNode(f(Node n, ConstantExpression c));

  Element operator [](Node node);
  Map<Node, DartType> get typesCache;

  /// Returns the [SendStructure] that describes the semantics of [node].
  SendStructure getSendStructure(Send node);

  /// Returns the [NewStructure] that describes the semantics of [node].
  NewStructure getNewStructure(NewExpression node);

  // TODO(johnniwinther): Investigate whether [Node] could be a [Send].
  Selector getSelector(Node node);
  Selector getGetterSelectorInComplexSendSet(SendSet node);
  Selector getOperatorSelectorInComplexSendSet(SendSet node);
  DartType getType(Node node);

  /// Returns the for-in loop variable for [node].
  Element getForInVariable(ForIn node);
  void setConstant(Node node, ConstantExpression constant);
  ConstantExpression getConstant(Node node);

  /// Returns the [FunctionElement] defined by [node].
  FunctionElement getFunctionDefinition(FunctionExpression node);

  /// Returns target constructor for the redirecting factory body [node].
  ConstructorElement getRedirectingTargetConstructor(
      RedirectingFactoryBody node);

  /**
   * Returns [:true:] if [node] is a type literal.
   *
   * Resolution marks this by setting the type on the node to be the
   * type that the literal refers to.
   */
  bool isTypeLiteral(Send node);

  /// Returns the type that the type literal [node] refers to.
  DartType getTypeLiteralType(Send node);

  /// Returns a list of nodes that potentially mutate [element] anywhere in its
  /// scope.
  List<Node> getPotentialMutations(VariableElement element);

  /// Returns a list of nodes that potentially mutate [element] in [node].
  List<Node> getPotentialMutationsIn(Node node, VariableElement element);

  /// Returns a list of nodes that potentially mutate [element] in a closure.
  List<Node> getPotentialMutationsInClosure(VariableElement element);

  /// Returns a list of nodes that access [element] within a closure in [node].
  List<Node> getAccessesByClosureIn(Node node, VariableElement element);

  /// Returns the jump target defined by [node].
  JumpTarget getTargetDefinition(Node node);

  /// Returns the jump target of the [node].
  JumpTarget getTargetOf(GotoStatement node);

  /// Returns the label defined by [node].
  LabelDefinition getLabelDefinition(Label node);

  /// Returns the label that [node] targets.
  LabelDefinition getTargetLabel(GotoStatement node);

  /// `true` if the [analyzedElement]'s source code contains a [TryStatement].
  bool get containsTryStatement;

  /// Returns native data stored with [node].
  getNativeData(Node node);
}

class TreeElementMapping extends TreeElements {
  final AnalyzableElement analyzedElement;
  Map<Spannable, Selector> _selectors;
  Map<Node, DartType> _types;

  Map<Node, DartType> _typesCache;
  Map<Node, DartType> get typesCache => _typesCache ??= <Node, DartType>{};

  Setlet<SourceSpan> _superUses;
  Map<Node, ConstantExpression> _constants;
  Map<VariableElement, List<Node>> _potentiallyMutated;
  Map<Node, Map<VariableElement, List<Node>>> _potentiallyMutatedIn;
  Map<VariableElement, List<Node>> _potentiallyMutatedInClosure;
  Map<Node, Map<VariableElement, List<Node>>> _accessedByClosureIn;
  Maplet<Send, SendStructure> _sendStructureMap;
  Maplet<NewExpression, NewStructure> _newStructureMap;
  bool containsTryStatement = false;

  /// Map from nodes to the targets they define.
  Map<Node, JumpTarget> _definedTargets;

  /// Map from goto statements to their targets.
  Map<GotoStatement, JumpTarget> _usedTargets;

  /// Map from labels to their label definition.
  Map<Label, LabelDefinition> _definedLabels;

  /// Map from labeled goto statements to the labels they target.
  Map<GotoStatement, LabelDefinition> _targetLabels;

  /// Map from nodes to native data.
  Map<Node, dynamic> _nativeData;

  final int hashCode = _hashCodeCounter = (_hashCodeCounter + 1).toUnsigned(30);
  static int _hashCodeCounter = 0;

  TreeElementMapping(this.analyzedElement);

  operator []=(Node node, Element element) {
    // TODO(johnniwinther): Simplify this invariant to use only declarations in
    // [TreeElements].
    assert(invariant(node, () {
      if (!element.isMalformed && analyzedElement != null && element.isPatch) {
        return analyzedElement.implementationLibrary.isPatch;
      }
      return true;
    }));
    // TODO(ahe): Investigate why the invariant below doesn't hold.
    // assert(invariant(node,
    //                  getTreeElement(node) == element ||
    //                  getTreeElement(node) == null,
    //                  message: '${getTreeElement(node)}; $element'));

    setTreeElement(node, element);
  }

  @override
  operator [](Node node) => getTreeElement(node);

  @override
  SendStructure getSendStructure(Send node) {
    if (_sendStructureMap == null) return null;
    return _sendStructureMap[node];
  }

  void setSendStructure(Send node, SendStructure sendStructure) {
    if (_sendStructureMap == null) {
      _sendStructureMap = new Maplet<Send, SendStructure>();
    }
    _sendStructureMap[node] = sendStructure;
  }

  @override
  NewStructure getNewStructure(NewExpression node) {
    if (_newStructureMap == null) return null;
    return _newStructureMap[node];
  }

  void setNewStructure(NewExpression node, NewStructure newStructure) {
    if (_newStructureMap == null) {
      _newStructureMap = new Maplet<NewExpression, NewStructure>();
    }
    _newStructureMap[node] = newStructure;
  }

  void setType(Node node, DartType type) {
    if (_types == null) {
      _types = new Maplet<Node, DartType>();
    }
    _types[node] = type;
  }

  @override
  DartType getType(Node node) => _types != null ? _types[node] : null;

  @override
  Iterable<SourceSpan> get superUses {
    return _superUses != null ? _superUses : const <SourceSpan>[];
  }

  void addSuperUse(SourceSpan span) {
    if (_superUses == null) {
      _superUses = new Setlet<SourceSpan>();
    }
    _superUses.add(span);
  }

  Selector _getSelector(Spannable node) {
    return _selectors != null ? _selectors[node] : null;
  }

  void _setSelector(Spannable node, Selector selector) {
    if (_selectors == null) {
      _selectors = new Maplet<Spannable, Selector>();
    }
    _selectors[node] = selector;
  }

  void setSelector(Node node, Selector selector) {
    _setSelector(node, selector);
  }

  @override
  Selector getSelector(Node node) => _getSelector(node);

  int getSelectorCount() => _selectors == null ? 0 : _selectors.length;

  void setGetterSelectorInComplexSendSet(SendSet node, Selector selector) {
    _setSelector(node.selector, selector);
  }

  @override
  Selector getGetterSelectorInComplexSendSet(SendSet node) {
    return _getSelector(node.selector);
  }

  void setOperatorSelectorInComplexSendSet(SendSet node, Selector selector) {
    _setSelector(node.assignmentOperator, selector);
  }

  @override
  Selector getOperatorSelectorInComplexSendSet(SendSet node) {
    return _getSelector(node.assignmentOperator);
  }

  @override
  Element getForInVariable(ForIn node) {
    return this[node];
  }

  @override
  void setConstant(Node node, ConstantExpression constant) {
    if (_constants == null) {
      _constants = new Maplet<Node, ConstantExpression>();
    }
    _constants[node] = constant;
  }

  @override
  ConstantExpression getConstant(Node node) {
    return _constants != null ? _constants[node] : null;
  }

  @override
  bool isTypeLiteral(Send node) {
    return getType(node) != null;
  }

  @override
  DartType getTypeLiteralType(Send node) {
    return getType(node);
  }

  @override
  List<Node> getPotentialMutations(VariableElement element) {
    if (_potentiallyMutated == null) return const <Node>[];
    List<Node> mutations = _potentiallyMutated[element];
    if (mutations == null) return const <Node>[];
    return mutations;
  }

  void registerPotentialMutation(VariableElement element, Node mutationNode) {
    if (_potentiallyMutated == null) {
      _potentiallyMutated = new Maplet<VariableElement, List<Node>>();
    }
    _potentiallyMutated.putIfAbsent(element, () => <Node>[]).add(mutationNode);
  }

  @override
  List<Node> getPotentialMutationsIn(Node node, VariableElement element) {
    if (_potentiallyMutatedIn == null) return const <Node>[];
    Map<VariableElement, List<Node>> mutationsIn = _potentiallyMutatedIn[node];
    if (mutationsIn == null) return const <Node>[];
    List<Node> mutations = mutationsIn[element];
    if (mutations == null) return const <Node>[];
    return mutations;
  }

  void registerPotentialMutationIn(
      Node contextNode, VariableElement element, Node mutationNode) {
    if (_potentiallyMutatedIn == null) {
      _potentiallyMutatedIn =
          new Maplet<Node, Map<VariableElement, List<Node>>>();
    }
    Map<VariableElement, List<Node>> mutationMap =
        _potentiallyMutatedIn.putIfAbsent(
            contextNode, () => new Maplet<VariableElement, List<Node>>());
    mutationMap.putIfAbsent(element, () => <Node>[]).add(mutationNode);
  }

  @override
  List<Node> getPotentialMutationsInClosure(VariableElement element) {
    if (_potentiallyMutatedInClosure == null) return const <Node>[];
    List<Node> mutations = _potentiallyMutatedInClosure[element];
    if (mutations == null) return const <Node>[];
    return mutations;
  }

  void registerPotentialMutationInClosure(
      VariableElement element, Node mutationNode) {
    if (_potentiallyMutatedInClosure == null) {
      _potentiallyMutatedInClosure = new Maplet<VariableElement, List<Node>>();
    }
    _potentiallyMutatedInClosure
        .putIfAbsent(element, () => <Node>[])
        .add(mutationNode);
  }

  @override
  List<Node> getAccessesByClosureIn(Node node, VariableElement element) {
    if (_accessedByClosureIn == null) return const <Node>[];
    Map<VariableElement, List<Node>> accessesIn = _accessedByClosureIn[node];
    if (accessesIn == null) return const <Node>[];
    List<Node> accesses = accessesIn[element];
    if (accesses == null) return const <Node>[];
    return accesses;
  }

  void setAccessedByClosureIn(
      Node contextNode, VariableElement element, Node accessNode) {
    if (_accessedByClosureIn == null) {
      _accessedByClosureIn = new Map<Node, Map<VariableElement, List<Node>>>();
    }
    Map<VariableElement, List<Node>> accessMap =
        _accessedByClosureIn.putIfAbsent(
            contextNode, () => new Maplet<VariableElement, List<Node>>());
    accessMap.putIfAbsent(element, () => <Node>[]).add(accessNode);
  }

  String toString() => 'TreeElementMapping($analyzedElement)';

  @override
  void forEachConstantNode(f(Node n, ConstantExpression c)) {
    if (_constants != null) {
      _constants.forEach(f);
    }
  }

  @override
  Element getFunctionDefinition(FunctionExpression node) {
    return this[node];
  }

  @override
  ConstructorElement getRedirectingTargetConstructor(
      RedirectingFactoryBody node) {
    return this[node];
  }

  void defineTarget(Node node, JumpTarget target) {
    if (_definedTargets == null) {
      _definedTargets = new Maplet<Node, JumpTarget>();
    }
    _definedTargets[node] = target;
  }

  void undefineTarget(Node node) {
    if (_definedTargets != null) {
      _definedTargets.remove(node);
      if (_definedTargets.isEmpty) {
        _definedTargets = null;
      }
    }
  }

  @override
  JumpTarget getTargetDefinition(Node node) {
    return _definedTargets != null ? _definedTargets[node] : null;
  }

  void registerTargetOf(GotoStatement node, JumpTarget target) {
    if (_usedTargets == null) {
      _usedTargets = new Maplet<GotoStatement, JumpTarget>();
    }
    _usedTargets[node] = target;
  }

  @override
  JumpTarget getTargetOf(GotoStatement node) {
    return _usedTargets != null ? _usedTargets[node] : null;
  }

  void defineLabel(Label label, LabelDefinition target) {
    if (_definedLabels == null) {
      _definedLabels = new Maplet<Label, LabelDefinition>();
    }
    _definedLabels[label] = target;
  }

  void undefineLabel(Label label) {
    if (_definedLabels != null) {
      _definedLabels.remove(label);
      if (_definedLabels.isEmpty) {
        _definedLabels = null;
      }
    }
  }

  @override
  LabelDefinition getLabelDefinition(Label label) {
    return _definedLabels != null ? _definedLabels[label] : null;
  }

  void registerTargetLabel(GotoStatement node, LabelDefinition label) {
    assert(node.target != null);
    if (_targetLabels == null) {
      _targetLabels = new Maplet<GotoStatement, LabelDefinition>();
    }
    _targetLabels[node] = label;
  }

  @override
  LabelDefinition getTargetLabel(GotoStatement node) {
    assert(node.target != null);
    return _targetLabels != null ? _targetLabels[node] : null;
  }

  void registerNativeData(Node node, dynamic nativeData) {
    if (_nativeData == null) {
      _nativeData = <Node, dynamic>{};
    }
    _nativeData[node] = nativeData;
  }

  @override
  dynamic getNativeData(Node node) {
    return _nativeData != null ? _nativeData[node] : null;
  }
}
