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

library vm.constants_native_effects;

import '../ast.dart';
import '../transformations/constants.dart';
import '../core_types.dart';

class VmConstantsBackend implements ConstantsBackend {
  final Map<String, String> defines;

  final Class immutableMapClass;
  final Class internalSymbolClass;
  final Class stringClass;
  final Field symbolNameField;

  VmConstantsBackend._(this.defines, this.immutableMapClass,
      this.internalSymbolClass, this.stringClass, this.symbolNameField);

  /// If [defines] is not `null` it will be used for handling
  /// `const {bool,...}.fromEnvironment()` otherwise the current VM's values
  /// will be used.
  factory VmConstantsBackend(Map<String, String> defines, CoreTypes coreTypes) {
    final Library coreLibrary = coreTypes.coreLibrary;
    final Class immutableMapClass = coreLibrary.classes
        .firstWhere((Class klass) => klass.name == '_ImmutableMap');
    assert(immutableMapClass != null);

    final Class internalSymbolClass = coreTypes.internalSymbolClass;
    assert(internalSymbolClass != null);

    final Class stringClass = coreTypes.stringClass;
    assert(stringClass != null);

    final Field symbolNameField =
        internalSymbolClass.fields.where((Field field) {
      return field.isInstanceMember && field.name.name == '_name';
    }).single;

    return new VmConstantsBackend._(defines, immutableMapClass,
        internalSymbolClass, stringClass, symbolNameField);
  }

  Constant buildConstantForNative(
      String nativeName,
      List<DartType> typeArguments,
      List<Constant> positionalArguments,
      Map<String, Constant> namedArguments,
      List<TreeNode> context,
      StaticInvocation node,
      ErrorReporter errorReporter,
      void abortEvaluation(String message)) {
    if ([
      'Bool_fromEnvironment',
      'Integer_fromEnvironment',
      'String_fromEnvironment'
    ].contains(nativeName)) {
      final argument = positionalArguments[0];
      if (argument is StringConstant) {
        final name = argument.value;

        Constant handleFromEnvironment<ValueT, ConstantT>(
            {ValueT defaultValue,
            ValueT parse(String v, {ValueT defaultValue}),
            ValueT fromEnvironment(String name, {ValueT defaultValue}),
            ConstantT makeConstant(ValueT val)}) {
          final Constant constant = namedArguments['defaultValue'];
          if (constant is ConstantT) {
            defaultValue = (constant as dynamic).value;
          } else if (constant is NullConstant) {
            defaultValue = null;
          }
          ValueT value;
          if (defines != null) {
            value = parse(defines[name], defaultValue: defaultValue);
          } else {
            value = fromEnvironment(name, defaultValue: defaultValue);
          }
          return value != null ? makeConstant(value) : new NullConstant();
        }

        switch (nativeName) {
          case 'Bool_fromEnvironment':
            return handleFromEnvironment<bool, BoolConstant>(
                defaultValue: false,
                parse: (String v, {bool defaultValue}) {
                  final String defineValue = defines[name];
                  return defineValue == 'true'
                      ? true
                      : (defineValue == 'false' ? false : defaultValue);
                },
                fromEnvironment: (v, {defaultValue}) =>
                    bool.fromEnvironment(v, defaultValue: defaultValue),
                makeConstant: (v) => BoolConstant(v));
          case 'Integer_fromEnvironment':
            return handleFromEnvironment<int, IntConstant>(
                defaultValue: null,
                parse: (String v, {int defaultValue}) {
                  final String defineValue = defines[name];
                  return defineValue != null
                      ? (int.tryParse(defineValue) ?? defaultValue)
                      : defaultValue;
                },
                fromEnvironment: (v, {defaultValue}) =>
                    int.fromEnvironment(v, defaultValue: defaultValue),
                makeConstant: (v) => new IntConstant(v));
          case 'String_fromEnvironment':
            return handleFromEnvironment<String, StringConstant>(
                defaultValue: null,
                parse: (String v, {String defaultValue}) {
                  final String defineValue = defines[name];
                  return defineValue ?? defaultValue;
                },
                fromEnvironment: (v, {defaultValue}) =>
                    String.fromEnvironment(v, defaultValue: defaultValue),
                makeConstant: (v) => new StringConstant(v));
        }
      } else {
        abortEvaluation(errorReporter.invalidDartType(
            context,
            node.arguments.positional.first,
            argument,
            new InterfaceType(stringClass)));
      }
    }

    throw 'No native effect registered for constant evaluation: $nativeName';
  }

  Constant lowerMapConstant(MapConstant constant) {
    // The _ImmutableMap class is implemented via one field pointing to a list
    // of key/value pairs -- see runtime/lib/immutable_map.dart!
    final List<Constant> kvListPairs =
        new List<Constant>(2 * constant.entries.length);
    for (int i = 0; i < constant.entries.length; i++) {
      final ConstantMapEntry entry = constant.entries[i];
      kvListPairs[2 * i] = entry.key;
      kvListPairs[2 * i + 1] = entry.value;
    }
    // This is a bit fishy, since we merge the key and the value type by
    // putting both into the same list.
    final kvListConstant = new ListConstant(const DynamicType(), kvListPairs);
    assert(immutableMapClass.fields.length == 1);
    final Field kvPairListField = immutableMapClass.fields[0];
    return new InstanceConstant(immutableMapClass.reference, <DartType>[
      constant.keyType,
      constant.valueType,
    ], <Reference, Constant>{
      kvPairListField.reference: kvListConstant,
    });
  }

  Constant lowerListConstant(ListConstant constant) {
    // Currently we let vipunen deal with the [ListConstant]s.
    return constant;
  }
}
