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

part of js_ast;

final _any = new AnyTypeRef._();
final _unknown = new UnknownTypeRef._();
final _null = new NullTypeRef();

/// JavaScript type reference, designed to support a subset of the type systems
/// of the Closure Compiler and TypeScript:
/// - https://developers.google.com/closure/compiler/docs/js-for-compiler#types
/// - https://github.com/Microsoft/TypeScript/blob/v1.8.0-beta/doc/spec.md#3
///
/// Note that some subtleties like "nullability" or "optionality" are handled
/// using unions (with a [NullTypeRef] or with an "undefined" named typeref).
/// Also, primitives aren't modeled differently than named / qualified types,
/// as it brings little value for now. Primitive-specific type formatting is
/// handled by the type printers (for instance, the knowledge that
/// `number|null` is just `number` in TypeScript, and is `number?` in Closure).
abstract class TypeRef extends Expression {
  int get precedenceLevel => PRIMARY;

  TypeRef();

  factory TypeRef.any() => _any;

  factory TypeRef.void_() => new TypeRef.named('void');

  factory TypeRef.unknown() => _unknown;

  factory TypeRef.generic(TypeRef rawType, Iterable<TypeRef> typeArgs) {
    if (typeArgs.isEmpty) {
      throw new ArgumentError.value(typeArgs, "typeArgs", "is empty");
    }
    return new GenericTypeRef(rawType, typeArgs.toList());
  }

  factory TypeRef.array([TypeRef elementType]) => new ArrayTypeRef(elementType);

  factory TypeRef.object([TypeRef keyType, TypeRef valueType]) {
    // TODO(ochafik): Roll out a dedicated ObjectTypeRef?
    var rawType = new TypeRef.named('Object');
    return keyType == null && valueType == null
        ? rawType
        : new GenericTypeRef(rawType, [keyType ?? _any, valueType ?? _any]);
  }

  factory TypeRef.function(
          [TypeRef returnType, Map<Identifier, TypeRef> paramTypes]) =>
      new FunctionTypeRef(returnType, paramTypes);

  factory TypeRef.record(Map<Identifier, TypeRef> types) =>
      new RecordTypeRef(types);

  factory TypeRef.string() => new TypeRef.named('string');

  factory TypeRef.number() => new TypeRef.named('number');

  factory TypeRef.undefined() => new TypeRef.named('undefined');

  factory TypeRef.boolean() => new TypeRef.named('boolean');

  factory TypeRef.qualified(List<Identifier> path) =>
      new QualifiedTypeRef(path);

  factory TypeRef.named(String name) =>
      new TypeRef.qualified(<Identifier>[new Identifier(name)]);

  bool get isAny => this is AnyTypeRef;
  bool get isUnknown => this is UnknownTypeRef;
  bool get isNull => this is NullTypeRef;

  TypeRef or(TypeRef other) => new UnionTypeRef([this, other]);

  TypeRef orUndefined() => or(new TypeRef.undefined());
  TypeRef orNull() => or(_null);

  TypeRef toOptional() => new OptionalTypeRef(this);
}

class AnyTypeRef extends TypeRef {
  AnyTypeRef._() : super();

  factory AnyTypeRef() => _any;
  T accept<T>(NodeVisitor<T> visitor) => visitor.visitAnyTypeRef(this);
  void visitChildren(NodeVisitor visitor) {}
  _clone() => new AnyTypeRef();
}

class NullTypeRef extends QualifiedTypeRef {
  NullTypeRef() : super([new Identifier("null")]);
  _clone() => new NullTypeRef();
}

class UnknownTypeRef extends TypeRef {
  UnknownTypeRef._() : super();

  factory UnknownTypeRef() => _unknown;
  T accept<T>(NodeVisitor<T> visitor) => visitor.visitUnknownTypeRef(this);
  void visitChildren(NodeVisitor visitor) {}
  _clone() => new UnknownTypeRef();
}

class QualifiedTypeRef extends TypeRef {
  final List<Identifier> path;
  QualifiedTypeRef(this.path);

  T accept<T>(NodeVisitor<T> visitor) => visitor.visitQualifiedTypeRef(this);
  void visitChildren(NodeVisitor visitor) =>
      path.forEach((p) => p.accept(visitor));
  _clone() => new QualifiedTypeRef(path);
}

class ArrayTypeRef extends TypeRef {
  final TypeRef elementType;
  ArrayTypeRef(this.elementType);
  T accept<T>(NodeVisitor<T> visitor) => visitor.visitArrayTypeRef(this);
  void visitChildren(NodeVisitor visitor) {
    elementType.accept(visitor);
  }

  _clone() => new ArrayTypeRef(elementType);
}

class GenericTypeRef extends TypeRef {
  final TypeRef rawType;
  final List<TypeRef> typeArgs;
  GenericTypeRef(this.rawType, this.typeArgs);

  T accept<T>(NodeVisitor<T> visitor) => visitor.visitGenericTypeRef(this);
  void visitChildren(NodeVisitor visitor) {
    rawType.accept(visitor);
    typeArgs.forEach((p) => p.accept(visitor));
  }

  _clone() => new GenericTypeRef(rawType, typeArgs);
}

class UnionTypeRef extends TypeRef {
  final List<TypeRef> types;
  UnionTypeRef(this.types);

  T accept<T>(NodeVisitor<T> visitor) => visitor.visitUnionTypeRef(this);
  void visitChildren(NodeVisitor visitor) {
    types.forEach((p) => p.accept(visitor));
  }

  _clone() => new UnionTypeRef(types);

  @override
  TypeRef or(TypeRef other) {
    if (types.contains(other)) return this;
    return new UnionTypeRef([]
      ..addAll(types)
      ..add(other));
  }
}

class OptionalTypeRef extends TypeRef {
  final TypeRef type;
  OptionalTypeRef(this.type);

  T accept<T>(NodeVisitor<T> visitor) => visitor.visitOptionalTypeRef(this);
  void visitChildren(NodeVisitor visitor) {
    type.accept(visitor);
  }

  _clone() => new OptionalTypeRef(type);

  @override
  TypeRef orUndefined() => this;
}

class RecordTypeRef extends TypeRef {
  final Map<Identifier, TypeRef> types;
  RecordTypeRef(this.types);

  T accept<T>(NodeVisitor<T> visitor) => visitor.visitRecordTypeRef(this);
  void visitChildren(NodeVisitor visitor) {
    types.values.forEach((p) => p.accept(visitor));
  }

  _clone() => new RecordTypeRef(types);
}

class FunctionTypeRef extends TypeRef {
  final TypeRef returnType;
  final Map<Identifier, TypeRef> paramTypes;
  FunctionTypeRef(this.returnType, this.paramTypes);

  T accept<T>(NodeVisitor<T> visitor) => visitor.visitFunctionTypeRef(this);
  void visitChildren(NodeVisitor visitor) {
    returnType.accept(visitor);
    paramTypes.forEach((n, t) {
      n.accept(visitor);
      t.accept(visitor);
    });
  }

  _clone() => new FunctionTypeRef(returnType, paramTypes);
}
