// 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 "ast.dart"
    show
        Class,
        Constructor,
        Extension,
        Field,
        Library,
        Name,
        Procedure,
        ProcedureKind,
        Reference,
        Typedef;

class ReferenceFromIndex {
  Map<Library, IndexedLibrary> _indexedLibraries =
      new Map<Library, IndexedLibrary>.identity();

  /// Add an entry mapping from *new* [library] to an index of the old library.
  void addIndexedLibrary(Library library, IndexedLibrary indexedLibrary) {
    assert(!_indexedLibraries.containsKey(library));
    _indexedLibraries[library] = indexedLibrary;
  }

  /// Lookup the new library and get an index of the old library.
  IndexedLibrary? lookupLibrary(Library library) => _indexedLibraries[library];
}

abstract class IndexedContainer {
  final Map<Name, Reference> _fieldReferences = new Map<Name, Reference>();
  final Map<Name, Reference> _getterReferences = new Map<Name, Reference>();
  final Map<Name, Reference> _setterReferences = new Map<Name, Reference>();

  Reference? lookupFieldReference(Name name) => _fieldReferences[name];
  Reference? lookupGetterReference(Name name) => _getterReferences[name];
  Reference? lookupSetterReference(Name name) => _setterReferences[name];

  Library get library;

  void _addProcedures(List<Procedure> procedures) {
    for (int i = 0; i < procedures.length; i++) {
      _addProcedure(procedures[i]);
    }
  }

  void _addProcedure(Procedure procedure) {
    Name name = procedure.name;
    if (procedure.isSetter) {
      assert(_setterReferences[name] == null);
      _setterReferences[name] = procedure.reference;
    } else {
      assert(_getterReferences[name] == null);
      assert(procedure.kind == ProcedureKind.Method ||
          procedure.kind == ProcedureKind.Getter ||
          procedure.kind == ProcedureKind.Operator);
      _getterReferences[name] = procedure.reference;
    }
  }

  void _addFields(List<Field> fields) {
    for (int i = 0; i < fields.length; i++) {
      Field field = fields[i];
      Name name = field.name;
      assert(_fieldReferences[name] == null);
      _fieldReferences[name] = field.fieldReference;
      assert(_getterReferences[name] == null);
      _getterReferences[name] = field.getterReference;
      if (field.hasSetter) {
        assert(_setterReferences[name] == null);
        _setterReferences[name] = field.setterReference!;
      }
    }
  }
}

class IndexedLibrary extends IndexedContainer {
  final Map<String, Typedef> _typedefs = new Map<String, Typedef>();
  final Map<String, Class> _classes = new Map<String, Class>();
  final Map<String, IndexedClass> _indexedClasses =
      new Map<String, IndexedClass>();
  final Map<String, Extension> _extensions = new Map<String, Extension>();
  @override
  final Library library;

  IndexedLibrary(this.library) {
    for (int i = 0; i < library.typedefs.length; i++) {
      Typedef typedef = library.typedefs[i];
      assert(_typedefs[typedef.name] == null);
      _typedefs[typedef.name] = typedef;
    }
    for (int i = 0; i < library.classes.length; i++) {
      Class c = library.classes[i];
      assert(_classes[c.name] == null);
      _classes[c.name] = c;
      assert(_indexedClasses[c.name] == null);
      _indexedClasses[c.name] = new IndexedClass._(c, library);
    }
    for (int i = 0; i < library.extensions.length; i++) {
      Extension extension = library.extensions[i];
      assert(_extensions[extension.name] == null);
      _extensions[extension.name] = extension;
    }
    _addProcedures(library.procedures);
    _addFields(library.fields);
  }

  Typedef? lookupTypedef(String name) => _typedefs[name];
  Class? lookupClass(String name) => _classes[name];
  IndexedClass? lookupIndexedClass(String name) => _indexedClasses[name];
  Extension? lookupExtension(String name) => _extensions[name];
}

class IndexedClass extends IndexedContainer {
  final Class cls;
  final Map<Name, Reference> _constructors = new Map<Name, Reference>();
  @override
  final Library library;

  IndexedClass._(this.cls, this.library) {
    for (int i = 0; i < cls.constructors.length; i++) {
      Constructor constructor = cls.constructors[i];
      _constructors[constructor.name] = constructor.reference;
    }
    for (int i = 0; i < cls.procedures.length; i++) {
      Procedure procedure = cls.procedures[i];
      if (procedure.isFactory) {
        _constructors[procedure.name] = procedure.reference;
      } else {
        _addProcedure(procedure);
      }
    }
    _addFields(cls.fields);
  }

  Reference? lookupConstructorReference(Name name) => _constructors[name];
}
