// Copyright (c) 2016, 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 fasta.builder_accessors;

export 'frontend_accessors.dart' show wrapInvalid;

import 'frontend_accessors.dart' show Accessor;

import 'package:kernel/ast.dart';

import 'package:kernel/core_types.dart' show CoreTypes;

import '../errors.dart' show internalError, printUnexpected;

import 'frontend_accessors.dart' as kernel
    show
        IndexAccessor,
        NullAwarePropertyAccessor,
        PropertyAccessor,
        StaticAccessor,
        SuperIndexAccessor,
        SuperPropertyAccessor,
        ThisIndexAccessor,
        ThisPropertyAccessor,
        VariableAccessor;

import 'frontend_accessors.dart' show buildIsNull, makeLet;

import 'kernel_builder.dart'
    show Builder, KernelClassBuilder, PrefixBuilder, TypeDeclarationBuilder;

abstract class BuilderHelper {
  Uri get uri;

  CoreTypes get coreTypes;

  Constructor lookupConstructor(Name name, {bool isSuper});

  Expression toSuperMethodInvocation(MethodInvocation node);

  Expression toValue(node);

  Member lookupSuperMember(Name name, {bool isSetter: false});

  builderToFirstExpression(Builder builder, String name, int charOffset);

  finishSend(Object receiver, Arguments arguments, int charOffset);

  Expression buildCompileTimeError(error, [int charOffset]);

  Initializer buildCompileTimeErrorIntializer(error, [int charOffset]);

  Expression buildStaticInvocation(Procedure target, Arguments arguments);

  Expression buildProblemExpression(Builder builder, String name);
}

abstract class BuilderAccessor implements Accessor {
  BuilderHelper get helper;

  int get charOffset;

  String get plainNameForRead;

  Uri get uri => helper.uri;

  CoreTypes get coreTypes => helper.coreTypes;

  String get plainNameForWrite => plainNameForRead;

  Expression buildForEffect() => buildSimpleRead();

  Initializer buildFieldInitializer(
      Map<String, FieldInitializer> initializers) {
    // TODO(ahe): This error message is really bad.
    return helper.buildCompileTimeErrorIntializer(
        "Can't use $plainNameForRead here.", charOffset);
  }

  Expression makeInvalidRead() {
    return throwNoSuchMethodError(
        plainNameForRead, new Arguments.empty(), uri, charOffset, coreTypes,
        isGetter: true);
  }

  Expression makeInvalidWrite(Expression value) {
    return throwNoSuchMethodError(plainNameForWrite,
        new Arguments(<Expression>[value]), uri, charOffset, coreTypes,
        isSetter: true);
  }

  TreeNode doInvocation(int charOffset, Arguments arguments);

  buildPropertyAccess(IncompleteSend send, bool isNullAware) {
    if (send is SendAccessor) {
      return buildMethodInvocation(
          buildSimpleRead(), send.name, send.arguments, send.charOffset,
          isNullAware: isNullAware);
    } else {
      return PropertyAccessor.make(helper, send.charOffset, buildSimpleRead(),
          send.name, null, null, isNullAware);
    }
  }

  Expression buildThrowNoSuchMethodError(Arguments arguments) {
    bool isGetter = false;
    if (arguments == null) {
      arguments = new Arguments.empty();
      isGetter = true;
    }
    return throwNoSuchMethodError(
        plainNameForWrite, arguments, uri, charOffset, coreTypes,
        isGetter: isGetter);
  }

  bool get isThisPropertyAccessor => false;
}

abstract class CompileTimeErrorAccessor implements Accessor {
  Expression buildError();

  Name get name => internalError("Unsupported operation.");

  String get plainNameForRead => name.name;

  withReceiver(Object receiver, {bool isNullAware}) => this;

  Initializer buildFieldInitializer(
      Map<String, FieldInitializer> initializers) {
    return new LocalInitializer(new VariableDeclaration.forValue(buildError()));
  }

  doInvocation(int charOffset, Arguments arguments) => this;

  buildPropertyAccess(IncompleteSend send, bool isNullAware) => this;

  buildThrowNoSuchMethodError(Arguments arguments) => this;

  Expression buildAssignment(Expression value, {bool voidContext: false}) {
    return buildError();
  }

  Expression buildCompoundAssignment(
      Name binaryOperator, Expression value, int charOffset,
      {bool voidContext: false, Procedure interfaceTarget}) {
    return buildError();
  }

  Expression buildPrefixIncrement(Name binaryOperator, int charOffset,
      {bool voidContext: false, Procedure interfaceTarget}) {
    return buildError();
  }

  Expression buildPostfixIncrement(Name binaryOperator, int charOffset,
      {bool voidContext: false, Procedure interfaceTarget}) {
    return buildError();
  }

  Expression buildNullAwareAssignment(Expression value, DartType type,
      {bool voidContext: false}) {
    return buildError();
  }

  Expression buildSimpleRead() => buildError();

  Expression makeInvalidRead() => buildError();

  Expression makeInvalidWrite(Expression value) => buildError();
}

class ThisAccessor extends BuilderAccessor {
  final BuilderHelper helper;

  final int charOffset;

  final bool isInitializer;

  final bool isSuper;

  ThisAccessor(this.helper, this.charOffset, this.isInitializer,
      {this.isSuper: false});

  String get plainNameForRead => internalError(isSuper ? "super" : "this");

  Expression buildSimpleRead() {
    if (!isSuper) {
      return new ThisExpression();
    } else {
      return helper.buildCompileTimeError(
          "Can't use `super` as an expression.", charOffset);
    }
  }

  Initializer buildFieldInitializer(
      Map<String, FieldInitializer> initializers) {
    String keyword = isSuper ? "super" : "this";
    return helper.buildCompileTimeErrorIntializer(
        "Can't use '$keyword' here, did you mean '$keyword()'?", charOffset);
  }

  buildPropertyAccess(IncompleteSend send, bool isNullAware) {
    if (isInitializer && send is SendAccessor) {
      return buildConstructorInitializer(
          send.charOffset, send.name, send.arguments);
    }
    if (send is SendAccessor) {
      // Notice that 'this' or 'super' can't be null. So we can ignore the
      // value of [isNullAware].
      MethodInvocation result = buildMethodInvocation(
          new ThisExpression(), send.name, send.arguments, charOffset);
      return isSuper ? helper.toSuperMethodInvocation(result) : result;
    } else {
      if (isSuper) {
        Member getter = helper.lookupSuperMember(send.name);
        Member setter = helper.lookupSuperMember(send.name, isSetter: true);
        return new SuperPropertyAccessor(
            helper, charOffset, send.name, getter, setter);
      } else {
        return new ThisPropertyAccessor(
            helper, charOffset, send.name, null, null);
      }
    }
  }

  doInvocation(int charOffset, Arguments arguments) {
    if (isInitializer) {
      return buildConstructorInitializer(charOffset, new Name(""), arguments);
    } else {
      return buildMethodInvocation(
          new ThisExpression(), new Name("call"), arguments, charOffset);
    }
  }

  Initializer buildConstructorInitializer(
      int charOffset, Name name, Arguments arguments) {
    Constructor constructor = helper.lookupConstructor(name, isSuper: isSuper);
    Initializer result;
    if (constructor == null) {
      result = new LocalInitializer(new VariableDeclaration.forValue(
          throwNoSuchMethodError(
              name.name, arguments, uri, charOffset, coreTypes,
              isSuper: isSuper)));
    } else if (isSuper) {
      result = new SuperInitializer(constructor, arguments);
    } else {
      result = new RedirectingInitializer(constructor, arguments);
    }
    return result..fileOffset = charOffset;
  }

  Expression buildAssignment(Expression value, {bool voidContext: false}) {
    return buildAssignmentError();
  }

  Expression buildNullAwareAssignment(Expression value, DartType type,
      {bool voidContext: false}) {
    return buildAssignmentError();
  }

  Expression buildCompoundAssignment(
      Name binaryOperator, Expression value, int charOffset,
      {bool voidContext: false, Procedure interfaceTarget}) {
    return buildAssignmentError();
  }

  Expression buildPrefixIncrement(Name binaryOperator, int charOffset,
      {bool voidContext: false, Procedure interfaceTarget}) {
    return buildAssignmentError();
  }

  Expression buildPostfixIncrement(Name binaryOperator, int charOffset,
      {bool voidContext: false, Procedure interfaceTarget}) {
    return buildAssignmentError();
  }

  Expression buildAssignmentError() {
    String message =
        isSuper ? "Can't assign to 'super'." : "Can't assign to 'this'.";
    return helper.buildCompileTimeError(message, charOffset);
  }

  toString() => "ThisAccessor($charOffset${isSuper ? ', super' : ''})";
}

abstract class IncompleteSend extends BuilderAccessor {
  final BuilderHelper helper;

  final int charOffset;

  final Name name;

  IncompleteSend(this.helper, this.charOffset, this.name);

  withReceiver(Object receiver, {bool isNullAware});
}

class IncompleteError extends IncompleteSend with CompileTimeErrorAccessor {
  final Object error;

  IncompleteError(BuilderHelper helper, int charOffset, this.error)
      : super(helper, charOffset, null);

  Expression buildError() {
    return helper.buildCompileTimeError(error, charOffset);
  }
}

class SendAccessor extends IncompleteSend {
  final Arguments arguments;

  SendAccessor(BuilderHelper helper, int charOffset, Name name, this.arguments)
      : super(helper, charOffset, name) {
    assert(arguments != null);
  }

  String get plainNameForRead => name.name;

  Expression buildSimpleRead() {
    return internalError("Unhandled");
  }

  Expression buildAssignment(Expression value, {bool voidContext: false}) {
    return internalError("Unhandled");
  }

  withReceiver(Object receiver, {bool isNullAware: false}) {
    if (receiver is TypeDeclarationBuilder) {
      /// `SomeType?.toString` is the same as `SomeType.toString`, not
      /// `(SomeType).toString`.
      isNullAware = false;
    }
    if (receiver is BuilderAccessor) {
      return receiver.buildPropertyAccess(this, isNullAware);
    }
    if (receiver is PrefixBuilder) {
      PrefixBuilder prefix = receiver;
      receiver = helper.builderToFirstExpression(
          prefix.exports[name.name], "${prefix.name}.${name.name}", charOffset);
      return helper.finishSend(receiver, arguments, charOffset);
    }
    Expression result;
    if (receiver is KernelClassBuilder) {
      Builder builder = receiver.findStaticBuilder(name.name, charOffset, uri);
      if (builder == null) {
        return buildThrowNoSuchMethodError(arguments);
      }
      if (builder.hasProblem) {
        result = helper.buildProblemExpression(builder, name.name);
      } else {
        Member target = builder.target;
        if (target != null) {
          if (target is Field) {
            result = buildMethodInvocation(
                new StaticGet(target), new Name("call"), arguments, charOffset,
                isNullAware: isNullAware);
          } else {
            result = helper.buildStaticInvocation(target, arguments);
          }
        } else {
          result = buildThrowNoSuchMethodError(arguments);
        }
      }
    } else {
      result = buildMethodInvocation(
          helper.toValue(receiver), name, arguments, charOffset,
          isNullAware: isNullAware);
    }
    return result..fileOffset = charOffset;
  }

  Expression buildNullAwareAssignment(Expression value, DartType type,
      {bool voidContext: false}) {
    return internalError("Unhandled");
  }

  Expression buildCompoundAssignment(
      Name binaryOperator, Expression value, int charOffset,
      {bool voidContext: false, Procedure interfaceTarget}) {
    return internalError("Unhandled");
  }

  Expression buildPrefixIncrement(Name binaryOperator, int charOffset,
      {bool voidContext: false, Procedure interfaceTarget}) {
    return internalError("Unhandled");
  }

  Expression buildPostfixIncrement(Name binaryOperator, int charOffset,
      {bool voidContext: false, Procedure interfaceTarget}) {
    return internalError("Unhandled");
  }

  Expression doInvocation(int charOffset, Arguments arguments) {
    return internalError("Unhandled");
  }

  toString() => "SendAccessor($charOffset, $name, $arguments)";
}

class IncompletePropertyAccessor extends IncompleteSend {
  IncompletePropertyAccessor(BuilderHelper helper, int charOffset, Name name)
      : super(helper, charOffset, name);

  String get plainNameForRead => name.name;

  Expression buildSimpleRead() => internalError("Unhandled");

  Expression buildAssignment(Expression value, {bool voidContext: false}) {
    return internalError("Unhandled");
  }

  withReceiver(Object receiver, {bool isNullAware: false}) {
    if (receiver is TypeDeclarationBuilder) {
      /// For reasons beyond comprehension, `SomeType?.toString` is the same as
      /// `SomeType.toString`, not `(SomeType).toString`. WTAF!?!
      //
      isNullAware = false;
    }
    if (receiver is BuilderAccessor) {
      return receiver.buildPropertyAccess(this, isNullAware);
    }
    if (receiver is PrefixBuilder) {
      PrefixBuilder prefix = receiver;
      return helper.builderToFirstExpression(
          prefix.exports[name.name], name.name, charOffset);
    }
    if (receiver is KernelClassBuilder) {
      Builder builder = receiver.findStaticBuilder(name.name, charOffset, uri);
      Member getter = builder?.target;
      Member setter;
      if (builder == null) {
        builder = receiver.findStaticBuilder(name.name, charOffset, uri,
            isSetter: true);
        if (builder == null) {
          return buildThrowNoSuchMethodError(null);
        }
        setter = builder.target;
      }
      if (builder.hasProblem) {
        return helper.buildProblemExpression(builder, name.name)
          ..fileOffset = charOffset;
      }
      if (getter is Field) {
        if (!getter.isFinal && !getter.isConst) {
          setter = getter;
        }
      } else if (getter is Procedure) {
        if (getter.isGetter) {
          builder = receiver.findStaticBuilder(name.name, charOffset, uri,
              isSetter: true);
          if (builder != null && !builder.hasProblem) {
            setter = builder.target;
          }
        }
      }
      if (getter == null && setter == null) {
        return internalError("No accessor for '$name'.");
      }
      return new StaticAccessor(helper, charOffset, getter, setter);
    }
    return PropertyAccessor.make(helper, charOffset, helper.toValue(receiver),
        name, null, null, isNullAware);
  }

  Expression buildNullAwareAssignment(Expression value, DartType type,
      {bool voidContext: false}) {
    return internalError("Unhandled");
  }

  Expression buildCompoundAssignment(
      Name binaryOperator, Expression value, int charOffset,
      {bool voidContext: false, Procedure interfaceTarget}) {
    return internalError("Unhandled");
  }

  Expression buildPrefixIncrement(Name binaryOperator, int charOffset,
      {bool voidContext: false, Procedure interfaceTarget}) {
    return internalError("Unhandled");
  }

  Expression buildPostfixIncrement(Name binaryOperator, int charOffset,
      {bool voidContext: false, Procedure interfaceTarget}) {
    return internalError("Unhandled");
  }

  Expression doInvocation(int charOffset, Arguments arguments) {
    return internalError("Unhandled");
  }

  toString() => "IncompletePropertyAccessor($charOffset, $name)";
}

class IndexAccessor extends kernel.IndexAccessor with BuilderAccessor {
  final BuilderHelper helper;

  IndexAccessor.internal(this.helper, int charOffset, Expression receiver,
      Expression index, Procedure getter, Procedure setter)
      : super.internal(receiver, index, getter, setter, charOffset);

  String get plainNameForRead => "[]";

  String get plainNameForWrite => "[]=";

  Expression doInvocation(int charOffset, Arguments arguments) {
    return buildMethodInvocation(
        buildSimpleRead(), new Name("call"), arguments, charOffset);
  }

  toString() => "IndexAccessor()";

  static BuilderAccessor make(
      BuilderHelper helper,
      int charOffset,
      Expression receiver,
      Expression index,
      Procedure getter,
      Procedure setter) {
    if (receiver is ThisExpression) {
      return new ThisIndexAccessor(helper, charOffset, index, getter, setter);
    } else {
      return new IndexAccessor.internal(
          helper, charOffset, receiver, index, getter, setter);
    }
  }
}

class PropertyAccessor extends kernel.PropertyAccessor with BuilderAccessor {
  final BuilderHelper helper;

  PropertyAccessor.internal(this.helper, int charOffset, Expression receiver,
      Name name, Member getter, Member setter)
      : super.internal(receiver, name, getter, setter, charOffset);

  String get plainNameForRead => name.name;

  bool get isThisPropertyAccessor => receiver is ThisExpression;

  Expression doInvocation(int charOffset, Arguments arguments) {
    return buildMethodInvocation(receiver, name, arguments, charOffset);
  }

  toString() => "PropertyAccessor()";

  static BuilderAccessor make(
      BuilderHelper helper,
      int charOffset,
      Expression receiver,
      Name name,
      Member getter,
      Member setter,
      bool isNullAware) {
    if (receiver is ThisExpression) {
      return new ThisPropertyAccessor(helper, charOffset, name, getter, setter);
    } else {
      return isNullAware
          ? new NullAwarePropertyAccessor(
              helper, charOffset, receiver, name, getter, setter, null)
          : new PropertyAccessor.internal(
              helper, charOffset, receiver, name, getter, setter);
    }
  }
}

class StaticAccessor extends kernel.StaticAccessor with BuilderAccessor {
  final BuilderHelper helper;

  final int charOffset;

  StaticAccessor(
      this.helper, this.charOffset, Member readTarget, Member writeTarget)
      : super(readTarget, writeTarget) {
    assert(readTarget != null || writeTarget != null);
  }

  String get plainNameForRead => (readTarget ?? writeTarget).name.name;

  Expression doInvocation(int charOffset, Arguments arguments) {
    if (readTarget == null || isFieldOrGetter(readTarget)) {
      return buildMethodInvocation(
          buildSimpleRead(), new Name("call"), arguments, charOffset);
    } else {
      return helper.buildStaticInvocation(readTarget, arguments)
        ..fileOffset = charOffset;
    }
  }

  toString() => "StaticAccessor()";
}

class SuperPropertyAccessor extends kernel.SuperPropertyAccessor
    with BuilderAccessor {
  final BuilderHelper helper;

  final int charOffset;

  SuperPropertyAccessor(
      this.helper, this.charOffset, Name name, Member getter, Member setter)
      : super(name, getter, setter);

  String get plainNameForRead => name.name;

  Expression doInvocation(int charOffset, Arguments arguments) {
    if (getter == null || isFieldOrGetter(getter)) {
      return buildMethodInvocation(
          buildSimpleRead(), new Name("call"), arguments, charOffset);
    } else {
      return new DirectMethodInvocation(new ThisExpression(), getter, arguments)
        ..fileOffset = charOffset;
    }
  }

  toString() => "SuperPropertyAccessor()";
}

class ThisIndexAccessor extends kernel.ThisIndexAccessor with BuilderAccessor {
  final BuilderHelper helper;

  final int charOffset;

  ThisIndexAccessor(this.helper, this.charOffset, Expression index,
      Procedure getter, Procedure setter)
      : super(index, getter, setter);

  String get plainNameForRead => "[]";

  String get plainNameForWrite => "[]=";

  Expression doInvocation(int charOffset, Arguments arguments) {
    return buildMethodInvocation(
        buildSimpleRead(), new Name("call"), arguments, charOffset);
  }

  toString() => "ThisIndexAccessor()";
}

class SuperIndexAccessor extends kernel.SuperIndexAccessor
    with BuilderAccessor {
  final BuilderHelper helper;

  final int charOffset;

  SuperIndexAccessor(this.helper, this.charOffset, Expression index,
      Member getter, Member setter)
      : super(index, getter, setter);

  String get plainNameForRead => "[]";

  String get plainNameForWrite => "[]=";

  Expression doInvocation(int charOffset, Arguments arguments) {
    return buildMethodInvocation(
        buildSimpleRead(), new Name("call"), arguments, charOffset);
  }

  toString() => "SuperIndexAccessor()";
}

class ThisPropertyAccessor extends kernel.ThisPropertyAccessor
    with BuilderAccessor {
  final BuilderHelper helper;

  final int charOffset;

  ThisPropertyAccessor(
      this.helper, this.charOffset, Name name, Member getter, Member setter)
      : super(name, getter, setter);

  String get plainNameForRead => name.name;

  bool get isThisPropertyAccessor => true;

  Expression doInvocation(int charOffset, Arguments arguments) {
    Member interfaceTarget = getter;
    if (interfaceTarget is Field) {
      // TODO(ahe): In strong mode we should probably rewrite this to
      // `this.name.call(arguments)`.
      interfaceTarget = null;
    }
    return buildMethodInvocation(
        new ThisExpression(), name, arguments, charOffset);
  }

  toString() => "ThisPropertyAccessor()";
}

class NullAwarePropertyAccessor extends kernel.NullAwarePropertyAccessor
    with BuilderAccessor {
  final BuilderHelper helper;

  final int charOffset;

  NullAwarePropertyAccessor(this.helper, this.charOffset, Expression receiver,
      Name name, Member getter, Member setter, DartType type)
      : super(receiver, name, getter, setter, type);

  String get plainNameForRead => name.name;

  Expression doInvocation(int charOffset, Arguments arguments) {
    return internalError("Not implemented yet.");
  }

  toString() => "NullAwarePropertyAccessor()";
}

class VariableAccessor extends kernel.VariableAccessor with BuilderAccessor {
  final BuilderHelper helper;

  VariableAccessor(this.helper, int charOffset, VariableDeclaration variable,
      [DartType promotedType])
      : super.internal(variable, charOffset, promotedType);

  String get plainNameForRead => variable.name;

  Expression doInvocation(int charOffset, Arguments arguments) {
    // Normally the offset is at the start of the token, but in this case,
    // because we insert a '.call', we want it at the end instead.
    return buildMethodInvocation(buildSimpleRead(), new Name("call"), arguments,
        charOffset + (variable.name?.length ?? 0));
  }

  toString() => "VariableAccessor()";
}

Expression throwNoSuchMethodError(String name, Arguments arguments, Uri uri,
    int charOffset, CoreTypes coreTypes,
    {bool isSuper: false, isGetter: false, isSetter: false}) {
  printUnexpected(uri, charOffset, "Method not found: '$name'.");
  Constructor constructor =
      coreTypes.getClass("dart:core", "NoSuchMethodError").constructors.first;
  return new Throw(new ConstructorInvocation(
      constructor,
      new Arguments(<Expression>[
        new NullLiteral(),
        new SymbolLiteral(name),
        new ListLiteral(arguments.positional),
        new MapLiteral(arguments.named.map((arg) {
          return new MapEntry(new SymbolLiteral(arg.name), arg.value);
        }).toList()),
        new NullLiteral()
      ])));
}

bool isFieldOrGetter(Member member) {
  return member is Field || (member is Procedure && member.isGetter);
}

Expression buildMethodInvocation(
    Expression receiver, Name name, Arguments arguments, int charOffset,
    {bool isNullAware: false}) {
  if (isNullAware) {
    VariableDeclaration variable = new VariableDeclaration.forValue(receiver);
    return makeLet(
        variable,
        new ConditionalExpression(
            buildIsNull(new VariableGet(variable)),
            new NullLiteral(),
            new MethodInvocation(new VariableGet(variable), name, arguments)
              ..fileOffset = charOffset,
            const DynamicType()));
  } else {
    return new MethodInvocation(receiver, name, arguments)
      ..fileOffset = charOffset;
  }
}
