// Copyright (c) 2014, 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.

/// Data structures representing an API definition, and visitor base classes
/// for visiting those data structures.
import 'dart:collection';

import 'package:html/dom.dart' as dom;

/// Toplevel container for the API.
class Api extends ApiNode {
  final String version;
  final List<Domain> domains;
  final Types types;
  final Refactorings refactorings;

  Api(this.version, this.domains, this.types, this.refactorings,
      dom.Element html,
      {bool experimental})
      : super(html, experimental, false);
}

/// Base class for objects in the API model.
class ApiNode {
  /// A flag to indicate if this API is experimental.
  final bool experimental;

  /// A flag to indicate if this API is deprecated.
  final bool deprecated;

  /// Html element representing this part of the API.
  final dom.Element html;

  ApiNode(this.html, bool experimental, bool deprecated)
      : experimental = experimental ?? false,
        deprecated = deprecated ?? false;
}

/// Base class for visiting the API definition.
abstract class ApiVisitor<T> {
  /// Dispatch the given [type] to the visitor.
  T visitTypeDecl(TypeDecl type) => type.accept(this);
  T visitTypeEnum(TypeEnum typeEnum);
  T visitTypeList(TypeList typeList);
  T visitTypeMap(TypeMap typeMap);
  T visitTypeObject(TypeObject typeObject);
  T visitTypeReference(TypeReference typeReference);

  T visitTypeUnion(TypeUnion typeUnion);
}

/// Definition of a single domain.
class Domain extends ApiNode {
  final String name;
  final List<Request> requests;
  final List<Notification> notifications;

  Domain(this.name, this.requests, this.notifications, dom.Element html,
      {bool experimental, bool deprecated})
      : super(html, experimental, deprecated);
}

/// API visitor that visits the entire API hierarchically by default.
class HierarchicalApiVisitor extends ApiVisitor {
  /// The API to visit.
  final Api api;

  HierarchicalApiVisitor(this.api);

  /// If [type] is a [TypeReference] that is defined in the API, follow the
  /// chain until a non-[TypeReference] is found, if possible.
  ///
  /// If it is not possible (because the chain ends with a [TypeReference] that
  /// is not defined in the API), then that final [TypeReference] is returned.
  TypeDecl resolveTypeReferenceChain(TypeDecl type) {
    while (type is TypeReference && api.types.containsKey(type.typeName)) {
      type = api.types[(type as TypeReference).typeName].type;
    }
    return type;
  }

  void visitApi() {
    api.domains.forEach(visitDomain);
    visitTypes(api.types);
    visitRefactorings(api.refactorings);
  }

  void visitDomain(Domain domain) {
    domain.requests.forEach(visitRequest);
    domain.notifications.forEach(visitNotification);
  }

  void visitNotification(Notification notification) {
    if (notification.params != null) {
      visitTypeDecl(notification.params);
    }
  }

  void visitRefactoring(Refactoring refactoring) {
    if (refactoring.feedback != null) {
      visitTypeDecl(refactoring.feedback);
    }
    if (refactoring.options != null) {
      visitTypeDecl(refactoring.options);
    }
  }

  void visitRefactorings(Refactorings refactorings) {
    refactorings?.forEach(visitRefactoring);
  }

  void visitRequest(Request request) {
    if (request.params != null) {
      visitTypeDecl(request.params);
    }
    if (request.result != null) {
      visitTypeDecl(request.result);
    }
  }

  void visitTypeDefinition(TypeDefinition typeDefinition) {
    visitTypeDecl(typeDefinition.type);
  }

  @override
  void visitTypeEnum(TypeEnum typeEnum) {
    typeEnum.values.forEach(visitTypeEnumValue);
  }

  void visitTypeEnumValue(TypeEnumValue typeEnumValue) {}

  @override
  void visitTypeList(TypeList typeList) {
    visitTypeDecl(typeList.itemType);
  }

  @override
  void visitTypeMap(TypeMap typeMap) {
    visitTypeDecl(typeMap.keyType);
    visitTypeDecl(typeMap.valueType);
  }

  @override
  void visitTypeObject(TypeObject typeObject) {
    typeObject.fields.forEach(visitTypeObjectField);
  }

  void visitTypeObjectField(TypeObjectField typeObjectField) {
    visitTypeDecl(typeObjectField.type);
  }

  @override
  void visitTypeReference(TypeReference typeReference) {}

  void visitTypes(Types types) {
    types.forEach(visitTypeDefinition);
  }

  @override
  void visitTypeUnion(TypeUnion typeUnion) {
    typeUnion.choices.forEach(visitTypeDecl);
  }
}

/// Description of a notification method.
class Notification extends ApiNode {
  /// Name of the domain enclosing this request.
  final String domainName;

  /// Name of the notification, without the domain prefix.
  final String event;

  /// Type of the object associated with the "params" key in the notification
  /// object, or null if the notification has no parameters.
  final TypeObject params;

  Notification(this.domainName, this.event, this.params, dom.Element html,
      {bool experimental})
      : super(html, experimental, false);

  /// Get the name of the notification, including the domain prefix.
  String get longEvent => '$domainName.$event';

  /// Get the full type of the notification object, including the common "id"
  /// and "error" fields.
  TypeDecl get notificationType {
    var fields = <TypeObjectField>[
      TypeObjectField('event', TypeReference('String', null), null,
          value: '$domainName.$event')
    ];
    if (params != null) {
      fields.add(TypeObjectField('params', params, null));
    }
    return TypeObject(fields, null);
  }
}

/// Description of a single refactoring.
class Refactoring extends ApiNode {
  /// Name of the refactoring. This should match one of the values allowed for
  /// RefactoringKind.
  final String kind;

  /// Type of the refactoring feedback, or null if the refactoring has no
  /// feedback.
  final TypeObject feedback;

  /// Type of the refactoring options, or null if the refactoring has no
  /// options.
  final TypeObject options;

  Refactoring(this.kind, this.feedback, this.options, dom.Element html,
      {bool experimental})
      : super(html, experimental, false);
}

/// A collection of refactoring definitions.
class Refactorings extends ApiNode with IterableMixin<Refactoring> {
  final List<Refactoring> refactorings;

  Refactorings(this.refactorings, dom.Element html, {bool experimental})
      : super(html, experimental, false);

  @override
  Iterator<Refactoring> get iterator => refactorings.iterator;
}

/// Description of a request method.
class Request extends ApiNode {
  /// Name of the domain enclosing this request.
  final String domainName;

  /// Name of the request, without the domain prefix.
  final String method;

  /// Type of the object associated with the "params" key in the request object,
  /// or null if the request has no parameters.
  final TypeObject params;

  /// Type of the object associated with the "result" key in the response
  /// object, or null if the response has no results.
  final TypeObject result;

  Request(
      this.domainName, this.method, this.params, this.result, dom.Element html,
      {bool experimental, bool deprecated})
      : super(html, experimental, deprecated);

  /// Get the name of the request, including the domain prefix.
  String get longMethod => '$domainName.$method';

  /// Get the full type of the request object, including the common "id" and
  /// "method" fields.
  TypeDecl get requestType {
    var fields = <TypeObjectField>[
      TypeObjectField('id', TypeReference('String', null), null),
      TypeObjectField('method', TypeReference('String', null), null,
          value: '$domainName.$method')
    ];
    if (params != null) {
      fields.add(TypeObjectField('params', params, null));
    }
    return TypeObject(fields, null);
  }

  /// Get the full type of the response object, including the common "id" and
  /// "error" fields.
  TypeDecl get responseType {
    var fields = <TypeObjectField>[
      TypeObjectField('id', TypeReference('String', null), null),
      TypeObjectField('error', TypeReference('RequestError', null), null,
          optional: true)
    ];
    if (result != null) {
      fields.add(TypeObjectField('result', result, null));
    }
    return TypeObject(fields, null);
  }
}

/// Base class for all possible types.
abstract class TypeDecl extends ApiNode {
  TypeDecl(dom.Element html, bool experimental, bool deprecated)
      : super(html, experimental, deprecated);

  T accept<T>(ApiVisitor<T> visitor);
}

/// Description of a named type definition.
class TypeDefinition extends ApiNode {
  final String name;
  final TypeDecl type;

  bool isExternal = false;

  TypeDefinition(this.name, this.type, dom.Element html,
      {bool experimental, bool deprecated})
      : super(html, experimental, deprecated);
}

/// Type of an enum. We represent enums in JSON as strings, so this type
/// declaration simply lists the allowed values.
class TypeEnum extends TypeDecl {
  final List<TypeEnumValue> values;

  TypeEnum(this.values, dom.Element html, {bool experimental, bool deprecated})
      : super(html, experimental, deprecated);

  @override
  T accept<T>(ApiVisitor<T> visitor) => visitor.visitTypeEnum(this);
}

/// Description of a single allowed value for an enum.
class TypeEnumValue extends ApiNode {
  final String value;

  TypeEnumValue(this.value, dom.Element html,
      {bool experimental, bool deprecated})
      : super(html, experimental, deprecated);
}

/// Type of a JSON list.
class TypeList extends TypeDecl {
  final TypeDecl itemType;

  TypeList(this.itemType, dom.Element html, {bool experimental})
      : super(html, experimental, false);

  @override
  T accept<T>(ApiVisitor<T> visitor) => visitor.visitTypeList(this);
}

/// Type of a JSON map.
class TypeMap extends TypeDecl {
  /// Type of map keys. Note that since JSON map keys must always be strings,
  /// this must either be a [TypeReference] for [String], or a [TypeReference]
  /// to a type which is defined in the API as an enum or a synonym for
  /// [String].
  final TypeReference keyType;

  /// Type of map values.
  final TypeDecl valueType;

  TypeMap(this.keyType, this.valueType, dom.Element html, {bool experimental})
      : super(html, experimental, false);

  @override
  T accept<T>(ApiVisitor<T> visitor) => visitor.visitTypeMap(this);
}

/// Type of a JSON object with specified fields, some of which may be optional.
class TypeObject extends TypeDecl {
  final List<TypeObjectField> fields;

  TypeObject(this.fields, dom.Element html,
      {bool experimental, bool deprecated})
      : super(html, experimental, deprecated);

  @override
  T accept<T>(ApiVisitor<T> visitor) => visitor.visitTypeObject(this);

  /// Return the field with the given [name], or null if there is no such field.
  TypeObjectField getField(String name) {
    for (var field in fields) {
      if (field.name == name) {
        return field;
      }
    }
    return null;
  }
}

/// Description of a single field in a [TypeObject].
class TypeObjectField extends ApiNode {
  final String name;
  final TypeDecl type;
  final bool optional;

  /// Value that the field is required to contain, or null if it may vary.
  final Object value;

  TypeObjectField(this.name, this.type, dom.Element html,
      {this.optional = false, this.value, bool experimental, bool deprecated})
      : super(html, experimental, deprecated);
}

/// A reference to a type which is either defined elsewhere in the API or which
/// is built-in ([String], [bool], or [int]).
class TypeReference extends TypeDecl {
  final String typeName;

  TypeReference(this.typeName, dom.Element html, {bool experimental})
      : super(html, experimental, false) {
    if (typeName.isEmpty) {
      throw Exception('Empty type name');
    }
  }

  @override
  T accept<T>(ApiVisitor<T> visitor) => visitor.visitTypeReference(this);
}

/// A collection of type definitions.
class Types extends ApiNode with IterableMixin<TypeDefinition> {
  final Map<String, TypeDefinition> types;

  List<String> importUris = <String>[];

  Types(this.types, dom.Element html, {bool experimental})
      : super(html, experimental, false);

  @override
  Iterator<TypeDefinition> get iterator => types.values.iterator;

  Iterable<String> get keys => types.keys;

  TypeDefinition operator [](String typeName) => types[typeName];

  bool containsKey(String typeName) => types.containsKey(typeName);
}

/// Type which represents a union among multiple choices.
class TypeUnion extends TypeDecl {
  final List<TypeDecl> choices;

  /// The field that is used to disambiguate this union
  final String field;

  TypeUnion(this.choices, this.field, dom.Element html, {bool experimental})
      : super(html, experimental, false);

  @override
  T accept<T>(ApiVisitor<T> visitor) => visitor.visitTypeUnion(this);
}
