// Copyright (c) 2017, 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:typed_data';

import '../base/api_signature.dart';
import '../fasta/parser.dart' show Listener, Parser, optional;
import '../fasta/parser/top_level_parser.dart';
import '../fasta/scanner.dart';
import '../fasta/scanner/token_constants.dart' show STRING_TOKEN;
import '../fasta/source/directive_listener.dart';
import 'format.dart';

/// Compute the [UnlinkedUnitBuilder] for the [content].
UnlinkedUnitBuilder computeUnlinkedUnit(List<int> salt, List<int> content) {
  // Scan the content.
  ScannerResult scanResult = _scan(content);
  Token token = scanResult.tokens;

  // Parse directives.
  var listener = new _UnlinkedDirectiveListener();
  new TopLevelParser(listener).parseUnit(token);

  // Parse to record function bodies.
  var parser = new _BodySkippingParser();
  parser.parseUnit(token);

  ApiSignature apiSignature = new ApiSignature();
  apiSignature.addBytes(salt);

  // Iterate over tokens and skip bodies.
  Iterator<_BodyRange> bodyIterator = parser.bodyRanges.iterator;
  bodyIterator.moveNext();
  for (; token.kind != EOF_TOKEN; token = token.next) {
    // Move to the body range that ends after the token.
    while (bodyIterator.current != null &&
        bodyIterator.current.last < token.charOffset) {
      bodyIterator.moveNext();
    }
    // If the current body range starts before or at the token, skip it.
    if (bodyIterator.current != null &&
        bodyIterator.current.first <= token.charOffset) {
      continue;
    }
    // The token is outside of a function body, add it.
    if (token is! ErrorToken) {
      apiSignature.addString(token.lexeme);
    }
  }

  return new UnlinkedUnitBuilder(
      apiSignature: apiSignature.toByteList(),
      imports: listener.imports.map(_toUnlinkedNamespaceDirective).toList(),
      exports: listener.exports.map(_toUnlinkedNamespaceDirective).toList(),
      parts: listener.parts.toList(),
      hasMixinApplication: listener.hasMixin);
}

/// Exclude all `native 'xyz';` token sequences.
void _excludeNativeClauses(Token token) {
  while (token.kind != EOF_TOKEN) {
    Token next = token.next;
    if (optional('native', next) &&
        next.next.kind == STRING_TOKEN &&
        optional(';', next.next.next)) {
      next = next.next.next;
      token.setNext(next);
    }
    token = next;
  }
}

/// Scan the content of the file.
ScannerResult _scan(List<int> content) {
  var zeroTerminatedBytes = new Uint8List(content.length + 1);
  zeroTerminatedBytes.setRange(0, content.length, content);
  ScannerResult result = scan(zeroTerminatedBytes);
  _excludeNativeClauses(result.tokens);
  return result;
}

/// Convert [NamespaceCombinator] into [UnlinkedCombinatorBuilder].
UnlinkedCombinatorBuilder _toUnlinkedCombinator(NamespaceCombinator c) =>
    new UnlinkedCombinatorBuilder(isShow: c.isShow, names: c.names.toList());

/// Convert [NamespaceDirective] into [UnlinkedNamespaceDirectiveBuilder].
UnlinkedNamespaceDirectiveBuilder _toUnlinkedNamespaceDirective(
        NamespaceDirective directive) =>
    new UnlinkedNamespaceDirectiveBuilder(
        uri: directive.uri,
        combinators: directive.combinators.map(_toUnlinkedCombinator).toList());

/// The char range of a function body.
class _BodyRange {
  /// The char offset of the first token in the range.
  final int first;

  /// The char offset of the last token in the range.
  final int last;

  _BodyRange(this.first, this.last);

  @override
  String toString() => '[$first, $last]';
}

/// The [Parser] that skips function bodies and remembers their token ranges.
class _BodySkippingParser extends Parser {
  final List<_BodyRange> bodyRanges = [];

  _BodySkippingParser() : super(new Listener());

  @override
  Token parseFunctionBody(
      Token token, bool ofFunctionExpression, bool allowAbstract) {
    Token next = token.next;
    if (identical('{', next.lexeme)) {
      Token close = skipBlock(token);
      bodyRanges.add(new _BodyRange(next.charOffset, close.charOffset));
      return close;
    }
    return super.parseFunctionBody(token, ofFunctionExpression, allowAbstract);
  }

  @override
  Token parseInvalidBlock(Token token) => skipBlock(token);
}

class _UnlinkedDirectiveListener extends DirectiveListener {
  bool hasMixin = false;

  @override
  void handleClassWithClause(Token withKeyword) {
    hasMixin = true;
    super.handleClassWithClause(withKeyword);
  }

  @override
  void handleNamedMixinApplicationWithClause(Token withKeyword) {
    hasMixin = true;
    super.handleNamedMixinApplicationWithClause(withKeyword);
  }
}
