// 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 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/token.dart';
import 'package:analyzer/dart/ast/visitor.dart';
import 'package:analyzer/source/line_info.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer_plugin/protocol/protocol_common.dart';

/**
 * A computer for [CompilationUnit] folding.
 */
class DartUnitFoldingComputer {
  final LineInfo _lineInfo;
  final CompilationUnit _unit;

  Directive _firstDirective, _lastDirective;
  final List<FoldingRegion> _foldingRegions = [];

  DartUnitFoldingComputer(this._lineInfo, this._unit);

  /**
   * Returns a list of folding regions, not `null`.
   */
  List<FoldingRegion> compute() {
    _addFileHeaderRegion();
    _unit.accept(new _DartUnitFoldingComputerVisitor(this));

    if (_firstDirective != null &&
        _lastDirective != null &&
        _firstDirective != _lastDirective) {
      _foldingRegions.add(new FoldingRegion(
          FoldingKind.DIRECTIVES,
          _firstDirective.keyword.end,
          _lastDirective.end - _firstDirective.keyword.end));
    }

    return _foldingRegions;
  }

  void _addFileHeaderRegion() {
    Token firstToken = _unit.beginToken;
    while (firstToken?.type == TokenType.SCRIPT_TAG) {
      firstToken = firstToken.next;
    }

    final Token firstComment = firstToken?.precedingComments;
    if (firstComment == null ||
        firstComment.type != TokenType.SINGLE_LINE_COMMENT) {
      return;
    }

    // Walk through the comments looking for a blank line to signal the end of
    // the file header.
    Token lastComment = firstComment;
    while (lastComment.next != null) {
      lastComment = lastComment.next;

      // If we ran out of tokens, use the original token as starting position.
      final hasBlankLine =
          _hasBlankLineBetween(lastComment, lastComment.next ?? firstToken);

      // Also considerd non-single-line-comments as the end
      final nextCommentIsDifferentType = lastComment.next != null &&
          lastComment.next.type != TokenType.SINGLE_LINE_COMMENT;

      if (hasBlankLine || nextCommentIsDifferentType) {
        _addRegion(firstComment.end, lastComment.end, FoldingKind.FILE_HEADER);
        break;
      }
    }
  }

  _addRegion(int startOffset, int endOffset, FoldingKind kind) {
    final CharacterLocation start = _lineInfo.getLocation(startOffset);
    final CharacterLocation end = _lineInfo.getLocation(endOffset);

    if (start.lineNumber != end.lineNumber) {
      _foldingRegions
          .add(new FoldingRegion(kind, startOffset, endOffset - startOffset));
    }
  }

  _addRegionForAnnotations(List<Annotation> annotations) {
    if (annotations.isNotEmpty) {
      _addRegion(annotations.first.name.end, annotations.last.end,
          FoldingKind.ANNOTATIONS);
    }
  }

  bool _hasBlankLineBetween(Token first, Token second) {
    final CharacterLocation firstLoc = _lineInfo.getLocation(first.end);
    final CharacterLocation secondLoc = _lineInfo.getLocation(second.offset);
    return secondLoc.lineNumber - firstLoc.lineNumber > 1;
  }

  _recordDirective(Directive node) {
    _firstDirective ??= node;
    _lastDirective = node;
  }
}

/**
 * An AST visitor for [DartUnitFoldingComputer].
 */
class _DartUnitFoldingComputerVisitor extends RecursiveAstVisitor<void> {
  final DartUnitFoldingComputer _computer;
  _DartUnitFoldingComputerVisitor(this._computer);

  @override
  void visitBlockFunctionBody(BlockFunctionBody node) {
    _computer._addRegion(node.block.leftBracket.end,
        node.block.rightBracket.offset, FoldingKind.FUNCTION_BODY);
    super.visitBlockFunctionBody(node);
  }

  @override
  void visitClassDeclaration(ClassDeclaration node) {
    _computer._addRegionForAnnotations(node.metadata);
    _computer._addRegion(
        node.leftBracket.end, node.rightBracket.offset, FoldingKind.CLASS_BODY);
    super.visitClassDeclaration(node);
  }

  @override
  void visitComment(Comment node) {
    if (node.isDocumentation) {
      _computer._addRegion(
          node.offset, node.end, FoldingKind.DOCUMENTATION_COMMENT);
    }
    super.visitComment(node);
  }

  @override
  void visitConstructorDeclaration(ConstructorDeclaration node) {
    _computer._addRegionForAnnotations(node.metadata);
    super.visitConstructorDeclaration(node);
  }

  @override
  void visitExportDirective(ExportDirective node) {
    _computer._recordDirective(node);
    super.visitExportDirective(node);
  }

  @override
  void visitFieldDeclaration(FieldDeclaration node) {
    _computer._addRegionForAnnotations(node.metadata);
    super.visitFieldDeclaration(node);
  }

  @override
  void visitFunctionDeclaration(FunctionDeclaration node) {
    _computer._addRegionForAnnotations(node.metadata);
    super.visitFunctionDeclaration(node);
  }

  @override
  void visitFunctionExpressionInvocation(FunctionExpressionInvocation node) {
    _computer._addRegion(node.argumentList.leftParenthesis.end,
        node.argumentList.rightParenthesis.offset, FoldingKind.INVOCATION);
    super.visitFunctionExpressionInvocation(node);
  }

  @override
  void visitImportDirective(ImportDirective node) {
    _computer._recordDirective(node);
    super.visitImportDirective(node);
  }

  @override
  void visitInstanceCreationExpression(InstanceCreationExpression node) {
    _computer._addRegion(node.argumentList.leftParenthesis.end,
        node.argumentList.rightParenthesis.offset, FoldingKind.INVOCATION);
    super.visitInstanceCreationExpression(node);
  }

  @override
  void visitLibraryDirective(LibraryDirective node) {
    _computer._recordDirective(node);
    super.visitLibraryDirective(node);
  }

  @override
  void visitListLiteral(ListLiteral node) {
    _computer._addRegion(
        node.leftBracket.end, node.rightBracket.offset, FoldingKind.LITERAL);
    super.visitListLiteral(node);
  }

  @override
  void visitMapLiteral(MapLiteral node) {
    _computer._addRegion(
        node.leftBracket.end, node.rightBracket.offset, FoldingKind.LITERAL);
    super.visitMapLiteral(node);
  }

  @override
  void visitMethodDeclaration(MethodDeclaration node) {
    _computer._addRegionForAnnotations(node.metadata);
    super.visitMethodDeclaration(node);
  }

  @override
  void visitMethodInvocation(MethodInvocation node) {
    _computer._addRegion(node.argumentList.leftParenthesis.end,
        node.argumentList.rightParenthesis.offset, FoldingKind.INVOCATION);
    super.visitMethodInvocation(node);
  }

  @override
  void visitMixinDeclaration(MixinDeclaration node) {
    _computer._addRegionForAnnotations(node.metadata);
    // TODO(brianwilkerson) Define `FoldingKind.MIXIN_BODY`?
    _computer._addRegion(
        node.leftBracket.end, node.rightBracket.offset, FoldingKind.CLASS_BODY);
    super.visitMixinDeclaration(node);
  }

  @override
  void visitPartDirective(PartDirective node) {
    _computer._recordDirective(node);
    super.visitPartDirective(node);
  }

  @override
  void visitPartOfDirective(PartOfDirective node) {
    _computer._recordDirective(node);
    super.visitPartOfDirective(node);
  }
}
