// Copyright (c) 2015, 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/analyzer.dart';
import 'package:analyzer/src/summary/format.dart';
import 'package:analyzer/src/summary/idl.dart';

/**
 * Compute the public namespace portion of the summary for the given [unit],
 * which is presumed to be an unresolved AST.
 */
UnlinkedPublicNamespaceBuilder computePublicNamespace(CompilationUnit unit) {
  _PublicNamespaceVisitor visitor = new _PublicNamespaceVisitor();
  unit.accept(visitor);
  return new UnlinkedPublicNamespaceBuilder(
      names: visitor.names, exports: visitor.exports, parts: visitor.parts);
}

/**
 * Serialize a [Configuration] into a [UnlinkedConfigurationBuilder].
 */
UnlinkedConfigurationBuilder serializeConfiguration(
    Configuration configuration) {
  return new UnlinkedConfigurationBuilder(
      name: configuration.name.components.map((i) => i.name).join('.'),
      value: configuration.value?.stringValue ?? 'true',
      uri: configuration.uri.stringValue);
}

class _CombinatorEncoder extends SimpleAstVisitor<UnlinkedCombinatorBuilder> {
  _CombinatorEncoder();

  List<String> encodeNames(NodeList<SimpleIdentifier> names) =>
      names.map((SimpleIdentifier id) => id.name).toList();

  @override
  UnlinkedCombinatorBuilder visitHideCombinator(HideCombinator node) {
    return new UnlinkedCombinatorBuilder(hides: encodeNames(node.hiddenNames));
  }

  @override
  UnlinkedCombinatorBuilder visitShowCombinator(ShowCombinator node) {
    return new UnlinkedCombinatorBuilder(
        shows: encodeNames(node.shownNames),
        offset: node.offset,
        end: node.end);
  }
}

class _PublicNamespaceVisitor extends RecursiveAstVisitor {
  final List<UnlinkedPublicNameBuilder> names = <UnlinkedPublicNameBuilder>[];
  final List<UnlinkedExportPublicBuilder> exports =
      <UnlinkedExportPublicBuilder>[];
  final List<String> parts = <String>[];

  _PublicNamespaceVisitor();

  UnlinkedPublicNameBuilder addNameIfPublic(
      String name, ReferenceKind kind, int numTypeParameters) {
    if (isPublic(name)) {
      UnlinkedPublicNameBuilder b = new UnlinkedPublicNameBuilder(
          name: name, kind: kind, numTypeParameters: numTypeParameters);
      names.add(b);
      return b;
    }
    return null;
  }

  bool isPublic(String name) => !name.startsWith('_');

  @override
  visitClassDeclaration(ClassDeclaration node) {
    UnlinkedPublicNameBuilder cls = addNameIfPublic(
        node.name.name,
        ReferenceKind.classOrEnum,
        node.typeParameters?.typeParameters?.length ?? 0);
    if (cls != null) {
      _addClassMembers(cls, node.members);
    }
  }

  @override
  visitClassTypeAlias(ClassTypeAlias node) {
    addNameIfPublic(node.name.name, ReferenceKind.classOrEnum,
        node.typeParameters?.typeParameters?.length ?? 0);
  }

  @override
  visitEnumDeclaration(EnumDeclaration node) {
    UnlinkedPublicNameBuilder enm =
        addNameIfPublic(node.name.name, ReferenceKind.classOrEnum, 0);
    if (enm != null) {
      enm.members.add(new UnlinkedPublicNameBuilder(
          name: 'values',
          kind: ReferenceKind.propertyAccessor,
          numTypeParameters: 0));
      for (EnumConstantDeclaration enumConstant in node.constants) {
        String name = enumConstant.name.name;
        if (isPublic(name)) {
          enm.members.add(new UnlinkedPublicNameBuilder(
              name: name,
              kind: ReferenceKind.propertyAccessor,
              numTypeParameters: 0));
        }
      }
    }
  }

  @override
  visitExportDirective(ExportDirective node) {
    exports.add(new UnlinkedExportPublicBuilder(
        uri: node.uri.stringValue,
        combinators: node.combinators
            .map((Combinator c) => c.accept(new _CombinatorEncoder()))
            .toList(),
        configurations:
            node.configurations.map(serializeConfiguration).toList()));
  }

  @override
  visitFunctionDeclaration(FunctionDeclaration node) {
    String name = node.name.name;
    if (node.isSetter) {
      name += '=';
    }
    addNameIfPublic(
        name,
        node.isGetter || node.isSetter
            ? ReferenceKind.topLevelPropertyAccessor
            : ReferenceKind.topLevelFunction,
        node.functionExpression.typeParameters?.typeParameters?.length ?? 0);
  }

  @override
  visitFunctionTypeAlias(FunctionTypeAlias node) {
    addNameIfPublic(node.name.name, ReferenceKind.typedef,
        node.typeParameters?.typeParameters?.length ?? 0);
  }

  @override
  visitGenericTypeAlias(GenericTypeAlias node) {
    addNameIfPublic(node.name.name, ReferenceKind.genericFunctionTypedef,
        node.typeParameters?.typeParameters?.length ?? 0);
  }

  @override
  visitMixinDeclaration(MixinDeclaration node) {
    UnlinkedPublicNameBuilder mixin = addNameIfPublic(
        node.name.name,
        ReferenceKind.classOrEnum,
        node.typeParameters?.typeParameters?.length ?? 0);
    if (mixin != null) {
      _addClassMembers(mixin, node.members);
    }
  }

  @override
  visitPartDirective(PartDirective node) {
    parts.add(node.uri.stringValue ?? '');
  }

  @override
  visitVariableDeclaration(VariableDeclaration node) {
    String name = node.name.name;
    addNameIfPublic(name, ReferenceKind.topLevelPropertyAccessor, 0);
    if (!node.isFinal && !node.isConst) {
      addNameIfPublic('$name=', ReferenceKind.topLevelPropertyAccessor, 0);
    }
  }

  void _addClassMembers(
      UnlinkedPublicNameBuilder builder, List<ClassMember> members) {
    for (ClassMember member in members) {
      if (member is FieldDeclaration && member.isStatic) {
        for (VariableDeclaration field in member.fields.variables) {
          String name = field.name.name;
          if (isPublic(name)) {
            builder.members.add(new UnlinkedPublicNameBuilder(
                name: name,
                kind: ReferenceKind.propertyAccessor,
                numTypeParameters: 0));
          }
        }
      }
      if (member is MethodDeclaration &&
          member.isStatic &&
          !member.isSetter &&
          !member.isOperator) {
        String name = member.name.name;
        if (isPublic(name)) {
          builder.members.add(new UnlinkedPublicNameBuilder(
              name: name,
              kind: member.isGetter
                  ? ReferenceKind.propertyAccessor
                  : ReferenceKind.method,
              numTypeParameters:
                  member.typeParameters?.typeParameters?.length ?? 0));
        }
      }
      if (member is ConstructorDeclaration && member.name != null) {
        String name = member.name.name;
        if (isPublic(name)) {
          builder.members.add(new UnlinkedPublicNameBuilder(
              name: name,
              kind: ReferenceKind.constructor,
              numTypeParameters: 0));
        }
      }
    }
  }
}
