// 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.

library analyzer.src.summary.public_namespace_visitor;

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) {
      for (ClassMember member in node.members) {
        if (member is FieldDeclaration && member.isStatic) {
          for (VariableDeclaration field in member.fields.variables) {
            String name = field.name.name;
            if (isPublic(name)) {
              cls.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)) {
            cls.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)) {
            cls.members.add(new UnlinkedPublicNameBuilder(
                name: name,
                kind: ReferenceKind.constructor,
                numTypeParameters: 0));
          }
        }
      }
    }
  }

  @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
  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);
    }
  }
}
