// Copyright (c) 2020, 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.

// @dart=2.9

import "dart:io" show File, Platform, stdout;
import "dart:typed_data" show Uint8List;

import 'package:_fe_analyzer_shared/src/parser/parser.dart'
    show IdentifierContext;

import 'package:_fe_analyzer_shared/src/scanner/token.dart'
    show CommentToken, Token;

import "package:front_end/src/fasta/util/direct_parser_ast.dart";

import 'package:front_end/src/fasta/util/direct_parser_ast_helper.dart';

void main(List<String> args) {
  Uri uri = Platform.script;
  uri = uri.resolve("../../kernel/lib/ast.dart");
  Uint8List bytes = new File.fromUri(uri).readAsBytesSync();
  DirectParserASTContentCompilationUnitEnd ast =
      getAST(bytes, includeBody: true, includeComments: true);
  Map<String, DirectParserASTContentTopLevelDeclarationEnd> classes = {};
  for (DirectParserASTContentTopLevelDeclarationEnd cls in ast.getClasses()) {
    DirectParserASTContentIdentifierHandle identifier = cls.getIdentifier();
    assert(classes[identifier.token] == null);
    classes[identifier.token.toString()] = cls;
  }

  Set<String> goodNames = {"TreeNode"};
  Map<Token, Replacement> replacements = {};
  for (MapEntry<String, DirectParserASTContentTopLevelDeclarationEnd> entry
      in classes.entries) {
    DirectParserASTContentTopLevelDeclarationEnd cls = entry.value;

    // Simple "class hierarchy" to only work on TreeNodes.
    if (goodNames.contains(entry.key)) {
      // Cached good.
    } else {
      // Check if good.
      String parent = getExtends(cls);
      DirectParserASTContentTopLevelDeclarationEnd parentCls = classes[parent];
      List<String> allParents = [parent];
      while (
          parent != null && parentCls != null && !goodNames.contains(parent)) {
        parent = getExtends(parentCls);
        allParents.add(parent);
        parentCls = classes[parent];
      }
      if (goodNames.contains(parent)) {
        goodNames.addAll(allParents);
      } else {
        continue;
      }
    }

    DirectParserASTContentClassDeclarationEnd classDeclaration =
        cls.getClassDeclaration();
    DirectParserASTContentClassOrMixinBodyEnd classOrMixinBody =
        classDeclaration.getClassOrMixinBody();

    Set<String> namedClassConstructors = {};
    Set<String> namedFields = {};
    for (DirectParserASTContentMemberEnd member
        in classOrMixinBody.getMembers()) {
      if (member.isClassConstructor()) {
        DirectParserASTContentClassConstructorEnd constructor =
            member.getClassConstructor();
        Token nameToken = constructor.beginToken;
        // String name = nameToken.lexeme;
        if (nameToken.next.lexeme == ".") {
          nameToken = nameToken.next.next;
          // name += ".$nameToken";
          namedClassConstructors.add(nameToken.lexeme);
        }
        if (nameToken.next.lexeme == ".") {
          throw "Unexpected";
        }
      } else if (member.isClassFields()) {
        DirectParserASTContentClassFieldsEnd classFields =
            member.getClassFields();
        Token identifierToken = classFields.getFieldIdentifiers().single.token;
        String identifier = identifierToken.toString();
        namedFields.add(identifier);
      }
    }

    // If there isn't a `frozen` field in `TreeNode` we insert one.
    if (entry.key == "TreeNode" && !namedFields.contains("frozen")) {
      Token classBraceToken = classOrMixinBody.beginToken;
      assert(classBraceToken.lexeme == "{");
      replacements[classBraceToken] = new Replacement(
          classBraceToken, classBraceToken, "{\n  bool frozen = false;");
    }

    for (DirectParserASTContentMemberEnd member
        in classOrMixinBody.getMembers()) {
      if (member.isClassConstructor()) {
        processConstructor(
            member, replacements, namedClassConstructors, namedFields);
      } else if (member.isClassFields()) {
        processField(member, entry, replacements);
      }
    }
  }
  Token token = ast.getBegin().token;

  int endOfLast = token.end;
  while (token != null) {
    CommentToken comment = token.precedingComments;
    while (comment != null) {
      if (comment.offset > endOfLast) {
        for (int i = endOfLast; i < comment.offset; i++) {
          int byte = bytes[i];
          stdout.writeCharCode(byte);
        }
      }

      stdout.write(comment.value());
      endOfLast = comment.end;
      comment = comment.next;
    }

    if (token.isEof) break;
    if (token.offset > endOfLast) {
      for (int i = endOfLast; i < token.offset; i++) {
        int byte = bytes[i];
        stdout.writeCharCode(byte);
      }
    }

    Replacement replacement = replacements[token];
    if (replacement != null) {
      stdout.write(replacement.replacement);
      token = replacement.endToken;
    } else {
      stdout.write(token.lexeme);
    }
    endOfLast = token.end;
    token = token.next;
  }
}

void processField(
    DirectParserASTContentMemberEnd member,
    MapEntry<String, DirectParserASTContentTopLevelDeclarationEnd> entry,
    Map<Token, Replacement> replacements) {
  DirectParserASTContentClassFieldsEnd classFields = member.getClassFields();

  if (classFields.count != 1) {
    throw "Notice ${classFields.count}";
  }

  Token identifierToken = classFields.getFieldIdentifiers().single.token;
  String identifier = identifierToken.toString();

  if (identifier == "frozen" && entry.key == "TreeNode") return;

  if (classFields.staticToken != null) {
    return;
  }
  bool isFinal = false;
  if (classFields.varFinalOrConst?.toString() == "final") {
    isFinal = true;
  }

  DirectParserASTContentTypeHandle type = classFields.getFirstType();
  String typeString = "dynamic";
  if (type != null) {
    Token token = type.beginToken;
    typeString = "";
    while (token != identifierToken) {
      typeString += " ${token.lexeme}";
      token = token.next;
    }
    typeString = typeString.trim();
  }

  DirectParserASTContentFieldInitializerEnd initializer =
      classFields.getFieldInitializer();
  String initializerString = "";
  if (initializer != null) {
    Token token = initializer.assignment;
    Token endToken = initializer.token;
    while (token != endToken) {
      initializerString += " ${token.lexeme}";
      token = token.next;
    }
    initializerString = initializerString.trim();
  }

  Token beginToken = classFields.beginToken;
  Token endToken = classFields.endToken;
  assert(beginToken != null);
  assert(endToken != null);

  String frozenCheckCode =
      """if (frozen) throw "Trying to modify frozen node!";""";

  if (identifier == "parent" && entry.key == "TreeNode") {
    // We update the parent for libraries for instance all the time (e.g.
    // when we link).
    frozenCheckCode = "";
  } else if (identifier == "transformerFlags" && entry.key == "Member") {
    // The verifier changes this for all libraries
    // (and then change it back again).
    frozenCheckCode = "";
  } else if (identifier == "initializer" && entry.key == "Field") {
    // The constant evaluator does some stuff here. Only allow that
    // when it's basically a no-op though!
    frozenCheckCode = """
    if (frozen) {
      if (_initializer is ConstantExpression && newValue is ConstantExpression) {
        if ((_initializer as ConstantExpression).constant == newValue.constant) {
          _initializer = newValue;
          return;
        }
      }
      throw "Trying to modify frozen node!";
    }""";
  }

  if (!isFinal) {
    replacements[beginToken] = new Replacement(beginToken, endToken, """
$typeString _$identifier$initializerString;
$typeString get $identifier => _$identifier;
void set $identifier($typeString newValue) {
    $frozenCheckCode
  _$identifier = newValue;
}""");
  } else {
    // Don't create setter for final field.
    // TODO: Possibly wrap a list for instance of a non-writable one.
    replacements[beginToken] = new Replacement(beginToken, endToken, """
final $typeString _$identifier$initializerString;
$typeString get $identifier => _$identifier;""");
  }
}

void processConstructor(
    DirectParserASTContentMemberEnd member,
    Map<Token, Replacement> replacements,
    Set<String> namedClassConstructors,
    Set<String> namedFields) {
  DirectParserASTContentClassConstructorEnd constructor =
      member.getClassConstructor();
  DirectParserASTContentFormalParametersEnd formalParameters =
      constructor.getFormalParameters();
  List<DirectParserASTContentFormalParameterEnd> parameters =
      formalParameters.getFormalParameters();

  for (DirectParserASTContentFormalParameterEnd parameter in parameters) {
    Token token = parameter.getBegin().token;
    if (token?.lexeme != "this") {
      continue;
    }
    // Here `this.foo` can just be replace with `this._foo`.
    Token afterDot = token.next.next;
    replacements[afterDot] = new Replacement(afterDot, afterDot, "_$afterDot");
  }

  DirectParserASTContentOptionalFormalParametersEnd optionalFormalParameters =
      formalParameters.getOptionalFormalParameters();
  Set<String> addInitializers = {};
  if (optionalFormalParameters != null) {
    List<DirectParserASTContentFormalParameterEnd> parameters =
        optionalFormalParameters.getFormalParameters();

    for (DirectParserASTContentFormalParameterEnd parameter in parameters) {
      Token token = parameter.getBegin().token;
      if (token?.lexeme != "this") {
        continue;
      }
      // Here `this.foo` can't just be replace with `this._foo` as it is
      // (possibly) named and we can't use private stuff in named.
      // Instead we replace it with `dynamic foo` here and add an
      // initializer `this._foo = foo`.
      Token afterDot = token.next.next;
      addInitializers.add(afterDot.lexeme);
      replacements[token] = new Replacement(token, token.next, "dynamic ");
    }
  }

  DirectParserASTContentInitializersEnd initializers =
      constructor.getInitializers();

  // First patch up any existing initializers.
  if (initializers != null) {
    List<DirectParserASTContentInitializerEnd> actualInitializers =
        initializers.getInitializers();
    for (DirectParserASTContentInitializerEnd initializer
        in actualInitializers) {
      Token token = initializer.getBegin().token;
      // This is only afterDot if there's a dot --- which (probably) is
      // only there if there's a `this`.
      Token afterDot = token.next.next;

      // We need to check it's not a redirecting call!
      // TODO(jensj): Handle redirects like this:
      //  class C {
      //    C();
      //    C.redirect() : this();
      //  }
      if (token.lexeme == "this" &&
          namedClassConstructors.contains(afterDot.lexeme)) {
        // Redirect!
        continue;
      }

      if (token.lexeme == "this") {
        // Here `this.foo` can just be replace with `this._foo`.
        assert(namedFields.contains(afterDot.lexeme));
        replacements[afterDot] =
            new Replacement(afterDot, afterDot, "_$afterDot");
      } else if (token.lexeme == "super") {
        // Don't try to patch this one.
      } else if (token.lexeme == "assert") {
        List<DirectParserASTContentIdentifierHandle> identifiers = initializer
            .recursivelyFind<DirectParserASTContentIdentifierHandle>();
        for (Token token in identifiers.map((e) => e.token)) {
          if (namedFields.contains(token.lexeme)) {
            replacements[token] = new Replacement(token, token, "_$token");
          }
        }
      } else {
        assert(namedFields.contains(token.lexeme),
            "${token.lexeme} isn't a known field among ${namedFields}");
        replacements[token] = new Replacement(token, token, "_$token");
      }
    }
  }

  // Then add any new ones.
  if (addInitializers.isNotEmpty && initializers == null) {
    // No initializers => Fake one by inserting `:` and all `_foo = foo`
    // entries.
    Token endToken = formalParameters.endToken;
    String initializerString =
        addInitializers.map((e) => "this._$e = $e").join(",\n");
    replacements[endToken] =
        new Replacement(endToken, endToken, ") : $initializerString");
  } else if (addInitializers.isNotEmpty) {
    // Add to existing initializer list. We add them as the first one(s)
    // so we don't have to insert before the potential super call.
    DirectParserASTContentInitializersBegin firstOne = initializers.getBegin();
    Token colon = firstOne.token;
    assert(colon.lexeme == ":");
    String initializerString =
        addInitializers.map((e) => "this._$e = $e").join(", ");
    replacements[colon] =
        new Replacement(colon, colon, ": $initializerString,");
  }

  // If there are anything in addInitializers we need to patch
  // up the body too -- if we replace `{this.foo}` with `{dynamic foo}`
  // and the body says `foo = 42;` before that would change the field,
  // now it will change the parameter value. We must patch up all usages
  // - even reads to work on things like
  //  class C {
  //    int field1;
  //    int field2;
  //    C(this.field1) : field2 = field1 + 1;
  //  }
  if (addInitializers.isNotEmpty) {
    DirectParserASTContentBlockFunctionBodyEnd blockFunctionBody =
        constructor.getBlockFunctionBody();
    if (blockFunctionBody != null) {
      List<DirectParserASTContentIdentifierHandle> identifiers =
          blockFunctionBody
              .recursivelyFind<DirectParserASTContentIdentifierHandle>();
      for (DirectParserASTContentIdentifierHandle identifier in identifiers) {
        Token token = identifier.token;
        IdentifierContext context = identifier.context;
        if (namedFields.contains(token.lexeme) &&
            addInitializers.contains(token.lexeme)) {
          // For now naively assume that if it's a continuation it says
          // `this.`
          if (!context.isContinuation) {
            replacements[token] = new Replacement(token, token, "_$token");
          }
        }
      }
    }
  }
}

class Replacement {
  final Token beginToken;
  final Token endToken;
  final String replacement;

  Replacement(this.beginToken, this.endToken, this.replacement);
}

String getExtends(DirectParserASTContentTopLevelDeclarationEnd cls) {
  DirectParserASTContentClassDeclarationEnd classDeclaration =
      cls.getClassDeclaration();

  DirectParserASTContentClassExtendsHandle classExtends =
      classDeclaration.getClassExtends();
  Token extendsKeyword = classExtends.extendsKeyword;
  if (extendsKeyword == null) {
    return null;
  } else {
    return extendsKeyword.next.toString();
  }
}

void debugDumpNode(DirectParserASTContent node) {
  node.children.forEach((element) {
    print("${element.what} (${element.deprecatedArguments}) "
        "(${element.children})");
  });
}

void debugDumpNodeRecursively(DirectParserASTContent node,
    {String indent = ""}) {
  print("$indent${node.what} (${node.deprecatedArguments})");
  if (node.children == null) return;
  node.children.forEach((element) {
    print("$indent${element.what} (${element.deprecatedArguments})");
    if (element.children != null) {
      element.children.forEach((element) {
        debugDumpNodeRecursively(element, indent: "  $indent");
      });
    }
  });
}
