// 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:collection/collection.dart';
import 'package:dartdoc/src/model/model.dart';
import 'package:dartdoc/src/model_utils.dart' as model_utils;
import 'package:meta/meta.dart';

/// A set of libraries, initialized after construction by accessing [libraries].
///
/// Do not cache return values of any methods or members excepting [libraries]
/// before finishing initialization of a [LibraryContainer].
abstract base class LibraryContainer implements Comparable<LibraryContainer> {
  final List<Library> libraries = [];

  late final List<Library> publicLibrariesSorted =
      libraries.wherePublic.sorted(byName);

  bool get hasPublicLibraries => libraries.any((e) => e.isPublic);

  LibraryContainer({required this.isSdk, required String enclosingName})
      : _enclosingName = enclosingName;

  /// The name of the container or object that this LibraryContainer is a part
  /// of.
  ///
  /// Used for sorting in [containerOrder].
  final String _enclosingName;

  /// Order by which this container should be sorted.
  @visibleForOverriding
  List<String> get containerOrder;

  /// Sorting key.
  ///
  /// [containerOrder] should contain these.
  @visibleForOverriding
  String get sortKey;

  /// Whether this container represents the Dart SDK.
  ///
  /// This can be false for containers that only represent a part of the SDK.
  final bool isSdk;

  /// Returns:
  /// * -1 if this container is listed in [containerOrder].
  /// * 0 if this container is named the same as the [_enclosingName].
  /// * 1 if this container represents the SDK.
  /// * 2 if this group has a name that contains the name [_enclosingName].
  /// * 3 otherwise.
  int get _group {
    if (containerOrder.contains(sortKey)) return -1;
    if (equalsIgnoreAsciiCase(sortKey, _enclosingName)) return 0;
    if (isSdk) return 1;
    if (sortKey.toLowerCase().contains(_enclosingName.toLowerCase())) return 2;
    return 3;
  }

  @override
  int compareTo(LibraryContainer other) {
    if (_group == other._group) {
      if (_group == -1) {
        return Comparable.compare(containerOrder.indexOf(sortKey),
            containerOrder.indexOf(other.sortKey));
      } else {
        return sortKey.toLowerCase().compareTo(other.sortKey.toLowerCase());
      }
    }
    return Comparable.compare(_group, other._group);
  }
}
