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

import 'dart:async';
import 'dart:collection';

import 'package:analysis_server/src/protocol_server.dart' hide Element;
import 'package:analysis_server/src/services/correction/name_suggestion.dart';
import 'package:analysis_server/src/services/correction/selection_analyzer.dart';
import 'package:analysis_server/src/services/correction/status.dart';
import 'package:analysis_server/src/services/correction/strings.dart';
import 'package:analysis_server/src/services/correction/util.dart';
import 'package:analysis_server/src/services/refactoring/naming_conventions.dart';
import 'package:analysis_server/src/services/refactoring/refactoring.dart';
import 'package:analysis_server/src/services/refactoring/refactoring_internal.dart';
import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/token.dart';
import 'package:analyzer/dart/ast/visitor.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/src/dart/ast/utilities.dart';
import 'package:analyzer/src/generated/java_core.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer_plugin/utilities/range_factory.dart';

const String _TOKEN_SEPARATOR = "\uFFFF";

/**
 * [ExtractLocalRefactoring] implementation.
 */
class ExtractLocalRefactoringImpl extends RefactoringImpl
    implements ExtractLocalRefactoring {
  final ResolvedUnitResult resolveResult;
  final int selectionOffset;
  final int selectionLength;
  SourceRange selectionRange;
  CorrectionUtils utils;

  String name;
  bool extractAll = true;
  final List<int> coveringExpressionOffsets = <int>[];
  final List<int> coveringExpressionLengths = <int>[];
  final List<String> names = <String>[];
  final List<int> offsets = <int>[];
  final List<int> lengths = <int>[];

  Expression rootExpression;
  Expression singleExpression;
  bool wholeStatementExpression = false;
  String stringLiteralPart;
  final List<SourceRange> occurrences = <SourceRange>[];
  final Map<Element, int> elementIds = <Element, int>{};
  Set<String> excludedVariableNames = new Set<String>();

  ExtractLocalRefactoringImpl(
      this.resolveResult, this.selectionOffset, this.selectionLength) {
    selectionRange = new SourceRange(selectionOffset, selectionLength);
    utils = new CorrectionUtils(resolveResult);
  }

  String get file => resolveResult.path;

  @override
  String get refactoringName => 'Extract Local Variable';

  CompilationUnit get unit => resolveResult.unit;

  CompilationUnitElement get unitElement => unit.declaredElement;

  String get _declarationKeyword {
    if (_isPartOfConstantExpression(rootExpression)) {
      return "const";
    } else {
      return "var";
    }
  }

  @override
  Future<RefactoringStatus> checkFinalConditions() {
    RefactoringStatus result = new RefactoringStatus();
    result.addStatus(checkName());
    return new Future.value(result);
  }

  @override
  Future<RefactoringStatus> checkInitialConditions() {
    RefactoringStatus result = new RefactoringStatus();
    // selection
    result.addStatus(_checkSelection());
    if (result.hasFatalError) {
      return new Future.value(result);
    }
    // occurrences
    _prepareOccurrences();
    _prepareOffsetsLengths();
    // names
    excludedVariableNames =
        utils.findPossibleLocalVariableConflicts(selectionOffset);
    _prepareNames();
    // done
    return new Future.value(result);
  }

  @override
  RefactoringStatus checkName() {
    RefactoringStatus result = new RefactoringStatus();
    result.addStatus(validateVariableName(name));
    if (excludedVariableNames.contains(name)) {
      result.addError(
          format("The name '{0}' is already used in the scope.", name));
    }
    return result;
  }

  @override
  Future<SourceChange> createChange() {
    SourceChange change = new SourceChange(refactoringName);
    // prepare occurrences
    List<SourceRange> occurrences;
    if (extractAll) {
      occurrences = this.occurrences;
    } else {
      occurrences = [selectionRange];
    }
    occurrences.sort((a, b) => a.offset - b.offset);
    // If the whole expression of a statement is selected, like '1 + 2',
    // then convert it into a variable declaration statement.
    if (wholeStatementExpression && occurrences.length == 1) {
      String keyword = _declarationKeyword;
      String declarationSource = '$keyword $name = ';
      SourceEdit edit =
          new SourceEdit(singleExpression.offset, 0, declarationSource);
      doSourceChange_addElementEdit(change, unitElement, edit);
      return new Future.value(change);
    }
    // prepare positions
    List<Position> positions = <Position>[];
    int occurrencesShift = 0;
    void addPosition(int offset) {
      positions.add(new Position(file, offset));
    }

    // add variable declaration
    {
      String declarationCode;
      int nameOffsetInDeclarationCode;
      if (stringLiteralPart != null) {
        declarationCode = 'var ';
        nameOffsetInDeclarationCode = declarationCode.length;
        declarationCode += "$name = '$stringLiteralPart';";
      } else {
        String keyword = _declarationKeyword;
        String initializerCode = utils.getRangeText(selectionRange);
        declarationCode = '$keyword ';
        nameOffsetInDeclarationCode = declarationCode.length;
        declarationCode += '$name = $initializerCode;';
      }
      // prepare location for declaration
      AstNode target = _findDeclarationTarget(occurrences);
      String eol = utils.endOfLine;
      // insert variable declaration
      if (target is Statement) {
        String prefix = utils.getNodePrefix(target);
        SourceEdit edit =
            new SourceEdit(target.offset, 0, declarationCode + eol + prefix);
        doSourceChange_addElementEdit(change, unitElement, edit);
        addPosition(edit.offset + nameOffsetInDeclarationCode);
        occurrencesShift = edit.replacement.length;
      } else if (target is ExpressionFunctionBody) {
        String prefix = utils.getNodePrefix(target.parent);
        String indent = utils.getIndent(1);
        Expression expr = target.expression;
        {
          String code = '{' + eol + prefix + indent;
          addPosition(
              target.offset + code.length + nameOffsetInDeclarationCode);
          code += declarationCode + eol;
          code += prefix + indent + 'return ';
          SourceEdit edit =
              new SourceEdit(target.offset, expr.offset - target.offset, code);
          occurrencesShift = target.offset + code.length - expr.offset;
          doSourceChange_addElementEdit(change, unitElement, edit);
        }
        doSourceChange_addElementEdit(
            change,
            unitElement,
            new SourceEdit(
                expr.end, target.end - expr.end, ';' + eol + prefix + '}'));
      }
    }
    // prepare replacement
    String occurrenceReplacement = name;
    if (stringLiteralPart != null) {
      occurrenceReplacement = "\${$name}";
      occurrencesShift += 2;
    }
    // replace occurrences with variable reference
    for (SourceRange range in occurrences) {
      SourceEdit edit = newSourceEdit_range(range, occurrenceReplacement);
      addPosition(range.offset + occurrencesShift);
      occurrencesShift += name.length - range.length;
      doSourceChange_addElementEdit(change, unitElement, edit);
    }
    // add the linked group
    change.addLinkedEditGroup(new LinkedEditGroup(
        positions,
        name.length,
        names
            .map((name) => new LinkedEditSuggestion(
                name, LinkedEditSuggestionKind.VARIABLE))
            .toList()));
    // done
    return new Future.value(change);
  }

  @override
  bool isAvailable() {
    return !_checkSelection().hasFatalError;
  }

  /**
   * Checks if [selectionRange] selects [Expression] which can be extracted, and
   * location of this [Expression] in AST allows extracting.
   */
  RefactoringStatus _checkSelection() {
    if (selectionOffset <= 0) {
      return new RefactoringStatus.fatal(
          'The selection offset must be greater than zero.');
    }
    if (selectionOffset + selectionLength >= resolveResult.content.length) {
      return new RefactoringStatus.fatal(
          'The selection end offset must be less then the length of the file.');
    }

    String selectionStr;
    // exclude whitespaces
    {
      selectionStr = utils.getRangeText(selectionRange);
      int numLeading = countLeadingWhitespaces(selectionStr);
      int numTrailing = countTrailingWhitespaces(selectionStr);
      int offset = selectionRange.offset + numLeading;
      int end = selectionRange.end - numTrailing;
      selectionRange = new SourceRange(offset, end - offset);
    }
    // get covering node
    AstNode coveringNode =
        new NodeLocator(selectionRange.offset, selectionRange.end)
            .searchWithin(unit);
    // compute covering expressions
    for (AstNode node = coveringNode; node != null; node = node.parent) {
      AstNode parent = node.parent;
      // skip some nodes
      if (node is ArgumentList ||
          node is AssignmentExpression ||
          node is NamedExpression ||
          node is TypeArgumentList) {
        continue;
      }
      if (node is ConstructorName || node is Label || node is TypeName) {
        rootExpression = null;
        coveringExpressionOffsets.clear();
        coveringExpressionLengths.clear();
        continue;
      }
      // cannot extract the name part of a property access
      if (parent is PrefixedIdentifier && parent.identifier == node ||
          parent is PropertyAccess && parent.propertyName == node) {
        continue;
      }
      // stop if not an Expression
      if (node is! Expression) {
        break;
      }
      // stop at void method invocations
      if (node is MethodInvocation) {
        MethodInvocation invocation = node;
        Element element = invocation.methodName.staticElement;
        if (element is ExecutableElement &&
            element.returnType != null &&
            element.returnType.isVoid) {
          if (rootExpression == null) {
            return new RefactoringStatus.fatal(
                'Cannot extract the void expression.',
                newLocation_fromNode(node));
          }
          break;
        }
      }
      // fatal selection problems
      if (coveringExpressionOffsets.isEmpty) {
        if (node is SimpleIdentifier) {
          if (node.inDeclarationContext()) {
            return new RefactoringStatus.fatal(
                'Cannot extract the name part of a declaration.',
                newLocation_fromNode(node));
          }
          Element element = node.staticElement;
          if (element is FunctionElement || element is MethodElement) {
            continue;
          }
        }
        if (parent is AssignmentExpression && parent.leftHandSide == node) {
          return new RefactoringStatus.fatal(
              'Cannot extract the left-hand side of an assignment.',
              newLocation_fromNode(node));
        }
      }
      // set selected expression
      if (coveringExpressionOffsets.isEmpty) {
        rootExpression = node;
      }
      // add the expression range
      coveringExpressionOffsets.add(node.offset);
      coveringExpressionLengths.add(node.length);
    }
    // We need an enclosing function.
    // If it has a block body, we can add a new variable declaration statement
    // into this block.  If it has an expression body, we can convert it into
    // the block body first.
    if (coveringNode == null ||
        coveringNode.thisOrAncestorOfType<FunctionBody>() == null) {
      return new RefactoringStatus.fatal(
          'An expression inside a function must be selected '
          'to activate this refactoring.');
    }
    // part of string literal
    if (coveringNode is StringLiteral) {
      if (selectionRange.length != 0 &&
          selectionRange.offset > coveringNode.offset &&
          selectionRange.end < coveringNode.end) {
        stringLiteralPart = selectionStr;
        return new RefactoringStatus();
      }
    }
    // single node selected
    if (rootExpression != null) {
      singleExpression = rootExpression;
      selectionRange = range.node(singleExpression);
      wholeStatementExpression = singleExpression.parent is ExpressionStatement;
      return new RefactoringStatus();
    }
    // invalid selection
    return new RefactoringStatus.fatal(
        'Expression must be selected to activate this refactoring.');
  }

  /**
   * Return an unique identifier for the given [Element], or `null` if [element]
   * is `null`.
   */
  int _encodeElement(Element element) {
    if (element == null) {
      return null;
    }
    int id = elementIds[element];
    if (id == null) {
      id = elementIds.length;
      elementIds[element] = id;
    }
    return id;
  }

  /**
   * Returns an [Element]-sensitive encoding of [tokens].
   * Each [Token] with a [LocalVariableElement] has a suffix of the element id.
   *
   * So, we can distinguish different local variables with the same name, if
   * there are multiple variables with the same name are declared in the
   * function we are searching occurrences in.
   */
  String _encodeExpressionTokens(Expression expr, List<Token> tokens) {
    // no expression, i.e. a part of a string
    if (expr == null) {
      return tokens.join(_TOKEN_SEPARATOR);
    }
    // prepare Token -> LocalElement map
    Map<Token, Element> map = new HashMap<Token, Element>(
        equals: (Token a, Token b) => a.lexeme == b.lexeme,
        hashCode: (Token t) => t.lexeme.hashCode);
    expr.accept(new _TokenLocalElementVisitor(map));
    // map and join tokens
    return tokens.map((Token token) {
      String tokenString = token.lexeme;
      // append token's Element id
      Element element = map[token];
      if (element != null) {
        int elementId = _encodeElement(element);
        if (elementId != null) {
          tokenString += '-$elementId';
        }
      }
      // done
      return tokenString;
    }).join(_TOKEN_SEPARATOR);
  }

  /**
   * Return the [AstNode] to defined the variable before.
   * It should be accessible by all the given [occurrences].
   */
  AstNode _findDeclarationTarget(List<SourceRange> occurrences) {
    List<AstNode> nodes = _findNodes(occurrences);
    AstNode commonParent = getNearestCommonAncestor(nodes);
    // Block
    if (commonParent is Block) {
      List<AstNode> firstParents = getParents(nodes[0]);
      int commonIndex = firstParents.indexOf(commonParent);
      return firstParents[commonIndex + 1];
    }
    // ExpressionFunctionBody
    AstNode expressionBody = _getEnclosingExpressionBody(commonParent);
    if (expressionBody != null) {
      return expressionBody;
    }
    // single Statement
    AstNode target = commonParent.thisOrAncestorOfType<Statement>();
    while (target.parent is! Block) {
      target = target.parent;
    }
    return target;
  }

  /**
   * Returns [AstNode]s at the offsets of the given [SourceRange]s.
   */
  List<AstNode> _findNodes(List<SourceRange> ranges) {
    List<AstNode> nodes = <AstNode>[];
    for (SourceRange range in ranges) {
      AstNode node = new NodeLocator(range.offset).searchWithin(unit);
      nodes.add(node);
    }
    return nodes;
  }

  /**
   * Returns the [ExpressionFunctionBody] that encloses [node], or `null`
   * if [node] is not enclosed with an [ExpressionFunctionBody].
   */
  ExpressionFunctionBody _getEnclosingExpressionBody(AstNode node) {
    while (node != null) {
      if (node is Statement) {
        return null;
      }
      if (node is ExpressionFunctionBody) {
        return node;
      }
      node = node.parent;
    }
    return null;
  }

  /**
   * Checks if it is OK to extract the node with the given [SourceRange].
   */
  bool _isExtractable(SourceRange range) {
    _ExtractExpressionAnalyzer analyzer = new _ExtractExpressionAnalyzer(range);
    utils.unit.accept(analyzer);
    return analyzer.status.isOK;
  }

  bool _isPartOfConstantExpression(AstNode node) {
    if (node is TypedLiteral) {
      return node.isConst;
    }
    if (node is InstanceCreationExpression) {
      return node.isConst;
    }
    if (node is ArgumentList ||
        node is ConditionalExpression ||
        node is BinaryExpression ||
        node is ParenthesizedExpression ||
        node is PrefixExpression ||
        node is Literal ||
        node is MapLiteralEntry) {
      return _isPartOfConstantExpression(node.parent);
    }
    return false;
  }

  void _prepareNames() {
    names.clear();
    if (stringLiteralPart != null) {
      names.addAll(getVariableNameSuggestionsForText(
          stringLiteralPart, excludedVariableNames));
    } else if (singleExpression != null) {
      names.addAll(getVariableNameSuggestionsForExpression(
          singleExpression.staticType,
          singleExpression,
          excludedVariableNames));
    }
  }

  /**
   * Prepares all occurrences of the source which matches given selection,
   * sorted by offsets.
   */
  void _prepareOccurrences() {
    occurrences.clear();
    elementIds.clear();
    // prepare selection
    String selectionSource;
    {
      String rawSelectionSource = utils.getRangeText(selectionRange);
      List<Token> selectionTokens = TokenUtils.getTokens(rawSelectionSource);
      selectionSource =
          _encodeExpressionTokens(rootExpression, selectionTokens);
    }
    // prepare enclosing function
    AstNode enclosingFunction;
    {
      AstNode selectionNode =
          new NodeLocator(selectionOffset).searchWithin(unit);
      enclosingFunction = getEnclosingExecutableNode(selectionNode);
    }
    // visit function
    enclosingFunction
        .accept(new _OccurrencesVisitor(this, occurrences, selectionSource));
  }

  void _prepareOffsetsLengths() {
    offsets.clear();
    lengths.clear();
    for (SourceRange occurrence in occurrences) {
      offsets.add(occurrence.offset);
      lengths.add(occurrence.length);
    }
  }
}

/**
 * [SelectionAnalyzer] for [ExtractLocalRefactoringImpl].
 */
class _ExtractExpressionAnalyzer extends SelectionAnalyzer {
  final RefactoringStatus status = new RefactoringStatus();

  _ExtractExpressionAnalyzer(SourceRange selection) : super(selection);

  /**
   * Records fatal error with given message.
   */
  void invalidSelection(String message) {
    _invalidSelection(message, null);
  }

  @override
  Object visitAssignmentExpression(AssignmentExpression node) {
    super.visitAssignmentExpression(node);
    Expression lhs = node.leftHandSide;
    if (_isFirstSelectedNode(lhs)) {
      _invalidSelection('Cannot extract the left-hand side of an assignment.',
          newLocation_fromNode(lhs));
    }
    return null;
  }

  @override
  Object visitSimpleIdentifier(SimpleIdentifier node) {
    super.visitSimpleIdentifier(node);
    if (_isFirstSelectedNode(node)) {
      // name of declaration
      if (node.inDeclarationContext()) {
        invalidSelection('Cannot extract the name part of a declaration.');
      }
      // method name
      Element element = node.staticElement;
      if (element is FunctionElement || element is MethodElement) {
        invalidSelection('Cannot extract a single method name.');
      }
      // name in property access
      AstNode parent = node.parent;
      if (parent is PrefixedIdentifier && identical(parent.identifier, node)) {
        invalidSelection('Cannot extract name part of a property access.');
      }
      if (parent is PropertyAccess && identical(parent.propertyName, node)) {
        invalidSelection('Cannot extract name part of a property access.');
      }
    }
    return null;
  }

  /**
   * Records fatal error with given [message] and [location].
   */
  void _invalidSelection(String message, Location location) {
    status.addFatalError(message, location);
    reset();
  }

  bool _isFirstSelectedNode(AstNode node) => node == firstSelectedNode;
}

class _HasStatementVisitor extends GeneralizingAstVisitor {
  bool result = false;

  _HasStatementVisitor();

  @override
  visitStatement(Statement node) {
    result = true;
  }
}

class _OccurrencesVisitor extends GeneralizingAstVisitor<void> {
  final ExtractLocalRefactoringImpl ref;
  final List<SourceRange> occurrences;
  final String selectionSource;

  _OccurrencesVisitor(this.ref, this.occurrences, this.selectionSource);

  @override
  void visitBinaryExpression(BinaryExpression node) {
    if (!_hasStatements(node)) {
      _tryToFindOccurrenceFragments(node);
      return;
    }
    super.visitBinaryExpression(node);
  }

  @override
  void visitExpression(Expression node) {
    if (ref._isExtractable(range.node(node))) {
      _tryToFindOccurrence(node);
    }
    super.visitExpression(node);
  }

  @override
  void visitStringLiteral(StringLiteral node) {
    if (ref.stringLiteralPart != null) {
      int length = ref.stringLiteralPart.length;
      String value = ref.utils.getNodeText(node);
      int lastIndex = 0;
      while (true) {
        int index = value.indexOf(ref.stringLiteralPart, lastIndex);
        if (index == -1) {
          break;
        }
        lastIndex = index + length;
        int start = node.offset + index;
        SourceRange range = new SourceRange(start, length);
        occurrences.add(range);
      }
      return;
    }
    visitExpression(node);
  }

  void _addOccurrence(SourceRange range) {
    if (range.intersects(ref.selectionRange)) {
      occurrences.add(ref.selectionRange);
    } else {
      occurrences.add(range);
    }
  }

  bool _hasStatements(AstNode root) {
    _HasStatementVisitor visitor = new _HasStatementVisitor();
    root.accept(visitor);
    return visitor.result;
  }

  void _tryToFindOccurrence(Expression node) {
    String nodeSource = ref.utils.getNodeText(node);
    List<Token> nodeTokens = TokenUtils.getTokens(nodeSource);
    nodeSource = ref._encodeExpressionTokens(node, nodeTokens);
    if (nodeSource == selectionSource) {
      _addOccurrence(range.node(node));
    }
  }

  void _tryToFindOccurrenceFragments(Expression node) {
    int nodeOffset = node.offset;
    String nodeSource = ref.utils.getNodeText(node);
    List<Token> nodeTokens = TokenUtils.getTokens(nodeSource);
    nodeSource = ref._encodeExpressionTokens(node, nodeTokens);
    // find "selection" in "node" tokens
    int lastIndex = 0;
    while (true) {
      // find next occurrence
      int index = nodeSource.indexOf(selectionSource, lastIndex);
      if (index == -1) {
        break;
      }
      lastIndex = index + selectionSource.length;
      // find start/end tokens
      int startTokenIndex =
          countMatches(nodeSource.substring(0, index), _TOKEN_SEPARATOR);
      int endTokenIndex =
          countMatches(nodeSource.substring(0, lastIndex), _TOKEN_SEPARATOR);
      Token startToken = nodeTokens[startTokenIndex];
      Token endToken = nodeTokens[endTokenIndex];
      // add occurrence range
      int start = nodeOffset + startToken.offset;
      int end = nodeOffset + endToken.end;
      _addOccurrence(range.startOffsetEndOffset(start, end));
    }
  }
}

class _TokenLocalElementVisitor extends RecursiveAstVisitor {
  final Map<Token, Element> map;

  _TokenLocalElementVisitor(this.map);

  visitSimpleIdentifier(SimpleIdentifier node) {
    Element element = node.staticElement;
    if (element is LocalVariableElement) {
      map[node.token] = element;
    }
  }
}
