// Copyright (c) 2015, 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 dart2js.serialization.constants;

import '../constants/constructors.dart';
import '../constants/expressions.dart';
import '../dart_types.dart';
import '../elements/elements.dart' show FieldElement;
import '../resolution/operators.dart';
import '../universe/call_structure.dart' show CallStructure;
import 'keys.dart';
import 'serialization.dart';

/// Visitor that serializes a [ConstantExpression] by encoding it into an
/// [ObjectEncoder].
///
/// This class is called from the [Serializer] when a [ConstantExpression] needs
/// serialization. The [ObjectEncoder] ensures that any [Element], [DartType],
/// and other [ConstantExpression] that the serialized [ConstantExpression]
/// depends upon are also serialized.
class ConstantSerializer
    extends ConstantExpressionVisitor<dynamic, ObjectEncoder> {
  const ConstantSerializer();

  @override
  void visitBinary(BinaryConstantExpression exp, ObjectEncoder encoder) {
    encoder.setEnum(Key.OPERATOR, exp.operator.kind);
    encoder.setConstant(Key.LEFT, exp.left);
    encoder.setConstant(Key.RIGHT, exp.right);
  }

  @override
  void visitConcatenate(
      ConcatenateConstantExpression exp, ObjectEncoder encoder) {
    encoder.setConstants(Key.ARGUMENTS, exp.expressions);
  }

  @override
  void visitConditional(
      ConditionalConstantExpression exp, ObjectEncoder encoder) {
    encoder.setConstant(Key.CONDITION, exp.condition);
    encoder.setConstant(Key.TRUE, exp.trueExp);
    encoder.setConstant(Key.FALSE, exp.falseExp);
  }

  @override
  void visitConstructed(
      ConstructedConstantExpression exp, ObjectEncoder encoder) {
    encoder.setElement(Key.ELEMENT, exp.target);
    encoder.setType(Key.TYPE, exp.type);
    encoder.setStrings(Key.NAMES, exp.callStructure.namedArguments);
    encoder.setConstants(Key.ARGUMENTS, exp.arguments);
  }

  @override
  void visitFunction(FunctionConstantExpression exp, ObjectEncoder encoder) {
    encoder.setElement(Key.ELEMENT, exp.element);
  }

  @override
  void visitIdentical(IdenticalConstantExpression exp, ObjectEncoder encoder) {
    encoder.setConstant(Key.LEFT, exp.left);
    encoder.setConstant(Key.RIGHT, exp.right);
  }

  @override
  void visitList(ListConstantExpression exp, ObjectEncoder encoder) {
    encoder.setType(Key.TYPE, exp.type);
    encoder.setConstants(Key.VALUES, exp.values);
  }

  @override
  void visitMap(MapConstantExpression exp, ObjectEncoder encoder) {
    encoder.setType(Key.TYPE, exp.type);
    encoder.setConstants(Key.KEYS, exp.keys);
    encoder.setConstants(Key.VALUES, exp.values);
  }

  @override
  void visitBool(BoolConstantExpression exp, ObjectEncoder encoder) {
    encoder.setBool(Key.VALUE, exp.primitiveValue);
  }

  @override
  void visitInt(IntConstantExpression exp, ObjectEncoder encoder) {
    encoder.setInt(Key.VALUE, exp.primitiveValue);
  }

  @override
  void visitDouble(DoubleConstantExpression exp, ObjectEncoder encoder) {
    encoder.setDouble(Key.VALUE, exp.primitiveValue);
  }

  @override
  void visitString(StringConstantExpression exp, ObjectEncoder encoder) {
    encoder.setString(Key.VALUE, exp.primitiveValue);
  }

  @override
  void visitNull(NullConstantExpression exp, ObjectEncoder encoder) {
    // No additional data needed.
  }

  @override
  void visitSymbol(SymbolConstantExpression exp, ObjectEncoder encoder) {
    encoder.setString(Key.NAME, exp.name);
  }

  @override
  void visitType(TypeConstantExpression exp, ObjectEncoder encoder) {
    encoder.setType(Key.TYPE, exp.type);
  }

  @override
  void visitUnary(UnaryConstantExpression exp, ObjectEncoder encoder) {
    encoder.setEnum(Key.OPERATOR, exp.operator.kind);
    encoder.setConstant(Key.EXPRESSION, exp.expression);
  }

  @override
  void visitVariable(VariableConstantExpression exp, ObjectEncoder encoder) {
    encoder.setElement(Key.ELEMENT, exp.element);
  }

  @override
  void visitPositional(PositionalArgumentReference exp, ObjectEncoder encoder) {
    encoder.setInt(Key.INDEX, exp.index);
  }

  @override
  void visitNamed(NamedArgumentReference exp, ObjectEncoder encoder) {
    encoder.setString(Key.NAME, exp.name);
  }

  @override
  void visitBoolFromEnvironment(
      BoolFromEnvironmentConstantExpression exp, ObjectEncoder encoder) {
    encoder.setConstant(Key.NAME, exp.name);
    if (exp.defaultValue != null) {
      encoder.setConstant(Key.DEFAULT, exp.defaultValue);
    }
  }

  @override
  void visitIntFromEnvironment(
      IntFromEnvironmentConstantExpression exp, ObjectEncoder encoder) {
    encoder.setConstant(Key.NAME, exp.name);
    if (exp.defaultValue != null) {
      encoder.setConstant(Key.DEFAULT, exp.defaultValue);
    }
  }

  @override
  void visitStringFromEnvironment(
      StringFromEnvironmentConstantExpression exp, ObjectEncoder encoder) {
    encoder.setConstant(Key.NAME, exp.name);
    if (exp.defaultValue != null) {
      encoder.setConstant(Key.DEFAULT, exp.defaultValue);
    }
  }

  @override
  void visitStringLength(
      StringLengthConstantExpression exp, ObjectEncoder encoder) {
    encoder.setConstant(Key.EXPRESSION, exp.expression);
  }

  @override
  void visitDeferred(DeferredConstantExpression exp, ObjectEncoder encoder) {
    encoder.setElement(Key.PREFIX, exp.prefix);
    encoder.setConstant(Key.EXPRESSION, exp.expression);
  }
}

/// Utility class for deserializing [ConstantExpression]s.
///
/// This is used by the [Deserializer].
class ConstantDeserializer {
  /// Deserializes a [ConstantExpression] from an [ObjectDecoder].
  ///
  /// The class is called from the [Deserializer] when a [ConstantExpression]
  /// needs deserialization. The [ObjectDecoder] ensures that any [Element],
  /// [DartType], and other [ConstantExpression] that the deserialized
  /// [ConstantExpression] depends upon are available.
  static ConstantExpression deserialize(ObjectDecoder decoder) {
    ConstantExpressionKind kind =
        decoder.getEnum(Key.KIND, ConstantExpressionKind.values);
    switch (kind) {
      case ConstantExpressionKind.BINARY:
        BinaryOperator operator = BinaryOperator
            .fromKind(decoder.getEnum(Key.OPERATOR, BinaryOperatorKind.values));
        return new BinaryConstantExpression(decoder.getConstant(Key.LEFT),
            operator, decoder.getConstant(Key.RIGHT));
      case ConstantExpressionKind.BOOL:
        return new BoolConstantExpression(decoder.getBool(Key.VALUE));
      case ConstantExpressionKind.BOOL_FROM_ENVIRONMENT:
        return new BoolFromEnvironmentConstantExpression(
            decoder.getConstant(Key.NAME),
            decoder.getConstant(Key.DEFAULT, isOptional: true));
      case ConstantExpressionKind.CONCATENATE:
        return new ConcatenateConstantExpression(
            decoder.getConstants(Key.ARGUMENTS));
      case ConstantExpressionKind.CONDITIONAL:
        return new ConditionalConstantExpression(
            decoder.getConstant(Key.CONDITION),
            decoder.getConstant(Key.TRUE),
            decoder.getConstant(Key.FALSE));
      case ConstantExpressionKind.CONSTRUCTED:
        List<String> names = decoder.getStrings(Key.NAMES, isOptional: true);
        List<ConstantExpression> arguments =
            decoder.getConstants(Key.ARGUMENTS, isOptional: true);
        return new ConstructedConstantExpression(
            decoder.getType(Key.TYPE),
            decoder.getElement(Key.ELEMENT),
            new CallStructure(arguments.length, names),
            arguments);
      case ConstantExpressionKind.DOUBLE:
        return new DoubleConstantExpression(decoder.getDouble(Key.VALUE));
      case ConstantExpressionKind.ERRONEOUS:
        break;
      case ConstantExpressionKind.FUNCTION:
        return new FunctionConstantExpression(decoder.getElement(Key.ELEMENT));
      case ConstantExpressionKind.IDENTICAL:
        return new IdenticalConstantExpression(
            decoder.getConstant(Key.LEFT), decoder.getConstant(Key.RIGHT));
      case ConstantExpressionKind.INT:
        return new IntConstantExpression(decoder.getInt(Key.VALUE));
      case ConstantExpressionKind.INT_FROM_ENVIRONMENT:
        return new IntFromEnvironmentConstantExpression(
            decoder.getConstant(Key.NAME),
            decoder.getConstant(Key.DEFAULT, isOptional: true));
      case ConstantExpressionKind.LIST:
        return new ListConstantExpression(decoder.getType(Key.TYPE),
            decoder.getConstants(Key.VALUES, isOptional: true));
      case ConstantExpressionKind.MAP:
        return new MapConstantExpression(
            decoder.getType(Key.TYPE),
            decoder.getConstants(Key.KEYS, isOptional: true),
            decoder.getConstants(Key.VALUES, isOptional: true));
      case ConstantExpressionKind.NULL:
        return new NullConstantExpression();
      case ConstantExpressionKind.STRING:
        return new StringConstantExpression(decoder.getString(Key.VALUE));
      case ConstantExpressionKind.STRING_FROM_ENVIRONMENT:
        return new StringFromEnvironmentConstantExpression(
            decoder.getConstant(Key.NAME),
            decoder.getConstant(Key.DEFAULT, isOptional: true));
      case ConstantExpressionKind.STRING_LENGTH:
        return new StringLengthConstantExpression(
            decoder.getConstant(Key.EXPRESSION));
      case ConstantExpressionKind.SYMBOL:
        return new SymbolConstantExpression(decoder.getString(Key.NAME));
      case ConstantExpressionKind.TYPE:
        return new TypeConstantExpression(decoder.getType(Key.TYPE));
      case ConstantExpressionKind.UNARY:
        UnaryOperator operator = UnaryOperator
            .fromKind(decoder.getEnum(Key.OPERATOR, UnaryOperatorKind.values));
        return new UnaryConstantExpression(
            operator, decoder.getConstant(Key.EXPRESSION));
      case ConstantExpressionKind.VARIABLE:
        return new VariableConstantExpression(decoder.getElement(Key.ELEMENT));

      case ConstantExpressionKind.POSITIONAL_REFERENCE:
        return new PositionalArgumentReference(decoder.getInt(Key.INDEX));
      case ConstantExpressionKind.NAMED_REFERENCE:
        return new NamedArgumentReference(decoder.getString(Key.NAME));
      case ConstantExpressionKind.DEFERRED:
        return new DeferredConstantExpression(
            decoder.getConstant(Key.EXPRESSION),
            decoder.getElement(Key.PREFIX));
      case ConstantExpressionKind.SYNTHETIC:
    }
    throw new UnsupportedError("Unexpected constant kind: ${kind} in $decoder");
  }
}

/// Visitor that serializes a [ConstantConstructor] by encoding it into an
/// [ObjectEncoder].
///
/// This class is called from the [ConstructorSerializer] when the [Serializer]
/// is serializing constant constructor. The [ObjectEncoder] ensures that any
/// [Element], [DartType], and [ConstantExpression] that the serialized
/// [ConstantConstructor] depends upon are also serialized.
class ConstantConstructorSerializer
    extends ConstantConstructorVisitor<dynamic, ObjectEncoder> {
  const ConstantConstructorSerializer();

  @override
  void visit(ConstantConstructor constantConstructor, ObjectEncoder encoder) {
    encoder.setEnum(Key.KIND, constantConstructor.kind);
    constantConstructor.accept(this, encoder);
  }

  @override
  void visitGenerative(
      GenerativeConstantConstructor constructor, ObjectEncoder encoder) {
    encoder.setType(Key.TYPE, constructor.type);
    MapEncoder defaults = encoder.createMap(Key.DEFAULTS);
    constructor.defaultValues.forEach((key, e) {
      defaults.setConstant('$key', e);
    });
    ListEncoder fields = encoder.createList(Key.FIELDS);
    constructor.fieldMap.forEach((FieldElement f, ConstantExpression e) {
      ObjectEncoder fieldSerializer = fields.createObject();
      fieldSerializer.setElement(Key.FIELD, f);
      fieldSerializer.setConstant(Key.CONSTANT, e);
    });
    if (constructor.superConstructorInvocation != null) {
      encoder.setConstant(
          Key.CONSTRUCTOR, constructor.superConstructorInvocation);
    }
  }

  @override
  void visitRedirectingFactory(
      RedirectingFactoryConstantConstructor constructor,
      ObjectEncoder encoder) {
    encoder.setConstant(
        Key.CONSTRUCTOR, constructor.targetConstructorInvocation);
  }

  @override
  void visitRedirectingGenerative(
      RedirectingGenerativeConstantConstructor constructor,
      ObjectEncoder encoder) {
    MapEncoder defaults = encoder.createMap(Key.DEFAULTS);
    constructor.defaultValues.forEach((key, ConstantExpression e) {
      defaults.setConstant('$key', e);
    });
    encoder.setConstant(Key.CONSTRUCTOR, constructor.thisConstructorInvocation);
  }
}

/// Utility class for deserializing [ConstantConstructor]s.
///
/// This is used by the [ConstructorElementZ].
class ConstantConstructorDeserializer {
  /// Deserializes a [ConstantConstructor] from an [ObjectDecoder].
  ///
  /// The class is called from the [Deserializer] when a constant constructor
  /// needs deserialization. The [ObjectDecoder] ensures that any [Element],
  /// [DartType], and [ConstantExpression] that the deserialized
  /// [ConstantConstructor] depends upon are available.
  static ConstantConstructor deserialize(ObjectDecoder decoder) {
    ConstantConstructorKind kind =
        decoder.getEnum(Key.KIND, ConstantConstructorKind.values);

    DartType readType() {
      return decoder.getType(Key.TYPE);
    }

    Map<dynamic /*int|String*/, ConstantExpression> readDefaults() {
      Map<dynamic, ConstantExpression> defaultValues =
          <dynamic, ConstantExpression>{};
      if (decoder.containsKey(Key.DEFAULTS)) {
        MapDecoder defaultsMap = decoder.getMap(Key.DEFAULTS);
        defaultsMap.forEachKey((String key) {
          int index = int.parse(key, onError: (_) => null);
          if (index != null) {
            defaultValues[index] = defaultsMap.getConstant(key);
          } else {
            defaultValues[key] = defaultsMap.getConstant(key);
          }
        });
      }
      return defaultValues;
    }

    Map<FieldElement, ConstantExpression> readFields() {
      Map<FieldElement, ConstantExpression> fieldMap =
          <FieldElement, ConstantExpression>{};
      if (decoder.containsKey(Key.FIELDS)) {
        ListDecoder fieldsList = decoder.getList(Key.FIELDS);
        for (int i = 0; i < fieldsList.length; i++) {
          ObjectDecoder object = fieldsList.getObject(i);
          FieldElement field = object.getElement(Key.FIELD);
          ConstantExpression constant = object.getConstant(Key.CONSTANT);
          fieldMap[field] = constant;
        }
      }
      return fieldMap;
    }

    ConstructedConstantExpression readConstructorInvocation() {
      return decoder.getConstant(Key.CONSTRUCTOR, isOptional: true);
    }

    switch (kind) {
      case ConstantConstructorKind.GENERATIVE:
        return new GenerativeConstantConstructor(readType(), readDefaults(),
            readFields(), readConstructorInvocation());
      case ConstantConstructorKind.REDIRECTING_GENERATIVE:
        return new RedirectingGenerativeConstantConstructor(
            readDefaults(), readConstructorInvocation());
      case ConstantConstructorKind.REDIRECTING_FACTORY:
        return new RedirectingFactoryConstantConstructor(
            readConstructorInvocation());
    }
  }
}
