class NpmPackageRootMetadataUtils {

  public static NestedAttributesMap createFullPackageMetadata(final NestedAttributesMap packageJson,
                                                              final String repositoryName,
                                                              final String sha1sum,
                                                              @Nullable final Repository repository,
                                                              final BiFunction<String, String, String> function)
  {
    String name = packageJson.get(NpmAttributes.P_NAME, String.class);
    String version = packageJson.get(NpmAttributes.P_VERSION, String.class);
    String now = NPM_TIMESTAMP_FORMAT.print(DateTime.now());

    NestedAttributesMap packageRoot = new NestedAttributesMap("metadata", new HashMap<String, Object>());

    packageRoot.set(META_ID, name);

    String packageRootLatestVersion = isNull(repository) ? "" : getPackageRootLatestVersion(packageJson, repository);

    packageRoot.child(DIST_TAGS).set(LATEST, function.apply(packageRootLatestVersion, version));

    packageRoot.child(NpmAttributes.P_USERS);

    NestedAttributesMap time = packageRoot.child(TIME);
    time.set(version, now);
    time.set(MODIFIED, now);
    time.set(CREATED, now);

    // Hoisting fields from version metadata
    setBugsUrl(packageJson, packageRoot);

    for (String field : FULL_HOISTED_FIELDS) {
      copy(packageRoot, packageJson, field);
    }

    // Copy version specific metadata fields
    NestedAttributesMap versionMap = packageRoot.child(VERSIONS).child(version);
    versionMap.set(META_ID, name + "@" + version);

    // required fields
    versionMap.child(DIST).set(NpmAttributes.P_SHASUM, sha1sum);
    versionMap.child(DIST).set(TARBALL,
        String.format("%s/repository/%s", repositoryName, NpmMetadataUtils.createRepositoryPath(name, version)));

    // optional fields
    for (String field : FULL_VERSION_MAP_FIELDS) {
      copy(versionMap, packageJson, field);
    }

    // needs to happen after copying fields
    NpmMetadataUtils.rewriteTarballUrl(repositoryName, packageRoot);

    return packageRoot;
  }

  private  NpmPackageRootMetadataUtils();

}