// Copyright (c) 2019, 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 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/type.dart';
import 'package:analyzer/src/generated/utilities_dart.dart';
import 'package:analyzer/src/summary/idl.dart';
import 'package:analyzer/src/summary2/linked_element_factory.dart';
import 'package:analyzer/src/summary2/linking_bundle_context.dart';
import 'package:analyzer/src/summary2/reference.dart';

/// The context of a linked bundle, with shared references.
class LinkedBundleContext {
  final LinkedElementFactory elementFactory;
  final LinkedNodeReferences referencesData;
  final List<Reference> _references;

  /// If the bundle is being linked, the reference to the linking context.
  /// Otherwise `null`, and we are not expected to access it.
  LinkingBundleContext linking;

  LinkedBundleContext(this.elementFactory, this.referencesData)
      : _references = List<Reference>.filled(referencesData.name.length, null,
            growable: true);

  T elementOfIndex<T extends Element>(int index) {
    var reference = referenceOfIndex(index);
    return elementFactory.elementOfReference(reference);
  }

  List<T> elementsOfIndexes<T extends Element>(List<int> indexList) {
    var result = List<T>(indexList.length);
    for (var i = 0; i < indexList.length; ++i) {
      var index = indexList[i];
      result[i] = elementOfIndex(index);
    }
    return result;
  }

  InterfaceType getInterfaceType(LinkedNodeType linkedType) {
    var type = getType(linkedType);
    if (type is InterfaceType && !type.element.isEnum) {
      return type;
    }
    return null;
  }

  DartType getType(LinkedNodeType linkedType) {
    var kind = linkedType.kind;
    if (kind == LinkedNodeTypeKind.dynamic_) {
      return DynamicTypeImpl.instance;
    } else if (kind == LinkedNodeTypeKind.genericTypeAlias) {
      var reference = referenceOfIndex(linkedType.genericTypeAliasReference);
      return GenericTypeAliasElementImpl.typeAfterSubstitution(
        elementFactory.elementOfReference(reference),
        linkedType.genericTypeAliasTypeArguments.map(getType).toList(),
      );
    } else if (kind == LinkedNodeTypeKind.function) {
      var returnType = getType(linkedType.functionReturnType);
      var formalParameters = linkedType.functionFormalParameters.map((p) {
        return ParameterElementImpl.synthetic(
          p.name,
          getType(p.type),
          _formalParameterKind(p.kind),
        );
      }).toList();
      return FunctionElementImpl.synthetic(formalParameters, returnType).type;
    } else if (kind == LinkedNodeTypeKind.interface) {
      var reference = referenceOfIndex(linkedType.interfaceClass);
      Element element = elementFactory.elementOfReference(reference);
      return InterfaceTypeImpl.explicit(
        element,
        linkedType.interfaceTypeArguments.map(getType).toList(),
      );
    } else if (kind == LinkedNodeTypeKind.typeParameter) {
      var reference = referenceOfIndex(linkedType.typeParameterParameter);
      Element element = elementFactory.elementOfReference(reference);
      return TypeParameterTypeImpl(element);
    } else if (kind == LinkedNodeTypeKind.void_) {
      return VoidTypeImpl.instance;
    } else {
      throw UnimplementedError('$kind');
    }
  }

  Reference referenceOfIndex(int index) {
    // When we are linking a bundle, we add new references.
    // So, grow the list of references when we have data for them.
    if (index >= _references.length) {
      if (referencesData.name.length > _references.length) {
        _references.length = referencesData.name.length;
      }
    }

    var reference = _references[index];
    if (reference != null) return reference;

    if (index == 0) {
      reference = elementFactory.rootReference;
      _references[index] = reference;
      return reference;
    }

    var parentIndex = referencesData.parent[index];
    var parent = referenceOfIndex(parentIndex);

    var name = referencesData.name[index];
    reference = parent.getChild(name);
    _references[index] = reference;

    return reference;
  }

  ParameterKind _formalParameterKind(LinkedNodeFormalParameterKind kind) {
    if (kind == LinkedNodeFormalParameterKind.optionalNamed) {
      return ParameterKind.NAMED;
    }
    if (kind == LinkedNodeFormalParameterKind.optionalPositional) {
      return ParameterKind.POSITIONAL;
    }
    return ParameterKind.REQUIRED;
  }
}
