/*
 * The Alluxio Open Foundation licenses this work under the Apache License, version 2.0
 * (the "License"). You may not use this work except in compliance with the License, which is
 * available at www.apache.org/licenses/LICENSE-2.0
 *
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
 * either express or implied, as more fully set forth in the License.
 *
 * See the NOTICE file distributed with this work for information regarding copyright ownership.
 */

package alluxio.cli.fs.command;

import alluxio.AlluxioURI;
import alluxio.annotation.PublicApi;
import alluxio.cli.CommandUtils;
import alluxio.client.file.FileSystemContext;
import alluxio.exception.AlluxioException;
import alluxio.exception.status.InvalidArgumentException;
import alluxio.grpc.ListStatusPOptions;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;

import java.io.IOException;

import javax.annotation.concurrent.ThreadSafe;

/**
 * Loads metadata about a path in the UFS to Alluxio. No data will be transferred.
 * This command is a client-side optimization without storing all returned `ls`
 * results, preventing OOM for massive amount of small files.
 */
@ThreadSafe
@PublicApi
public class LoadMetadataCommand extends AbstractFileSystemCommand {
  private static final Option RECURSIVE_OPTION =
      Option.builder("R")
          .required(false)
          .hasArg(false)
          .desc("load metadata subdirectories recursively")
          .build();

  /**
   * Constructs a new instance to load metadata for the given Alluxio path from UFS.
   *
   * @param fsContext the filesystem of Alluxio
   */
  public LoadMetadataCommand(FileSystemContext fsContext) {
    super(fsContext);
  }

  @Override
  public String getCommandName() {
    return "loadMetadata";
  }

  @Override
  public Options getOptions() {
    return new Options().addOption(RECURSIVE_OPTION);
  }

  @Override
  protected void runPlainPath(AlluxioURI plainPath, CommandLine cl)
      throws AlluxioException, IOException {
    loadMetadata(plainPath, cl.hasOption(RECURSIVE_OPTION.getOpt()));
  }

  @Override
  public int run(CommandLine cl) throws AlluxioException, IOException {
    String[] args = cl.getArgs();
    AlluxioURI path = new AlluxioURI(args[0]);
    runWildCardCmd(path, cl);

    return 0;
  }

  private void loadMetadata(AlluxioURI path, boolean recursive) throws IOException {
    try {
      ListStatusPOptions options = ListStatusPOptions.newBuilder()
          .setRecursive(recursive).build();
      mFileSystem.loadMetadata(path, options);
    } catch (AlluxioException e) {
      throw new IOException(e.getMessage());
    }
  }

  @Override
  public String getUsage() {
    return "loadMetadata [-R] <path>";
  }

  @Override
  public String getDescription() {
    return "Loads metadata for the given Alluxio path from the under file system.";
  }

  @Override
  public void validateArgs(CommandLine cl) throws InvalidArgumentException {
    CommandUtils.checkNumOfArgsNoLessThan(this, cl, 1);
  }
}

@@ -776,32 +776,84 @@
 umentException;%0A
+import alluxio.grpc.FileSystemMasterCommonPOptions;%0A
 import alluxio.g
@@ -1608,16 +1608,233 @@
 ild();%0A%0A
+  private static final Option FORCE_OPTION =%0A      Option.builder(%22F%22)%0A          .required(false)%0A          .hasArg(false)%0A          .desc(%22update the metadata of the existing sub file forcibly%22)%0A          .build();%0A%0A
   /**%0A  
@@ -2209,16 +2209,25 @@
 ptions()
+%0A        
 .addOpti
@@ -2246,16 +2246,49 @@
 _OPTION)
+%0A        .addOption(FORCE_OPTION)
 ;%0A  %7D%0A%0A 
@@ -2478,16 +2478,61 @@
 etOpt())
+,%0A        cl.hasOption(FORCE_OPTION.getOpt())
 );%0A  %7D%0A%0A
@@ -2808,16 +2808,31 @@
 ecursive
+, boolean force
 ) throws
@@ -2881,16 +2881,52 @@
 Options 
+options;%0A      if (force) %7B%0A        
 options 
@@ -2969,16 +2969,18 @@
         
+  
 .setRecu
@@ -2995,25 +2995,265 @@
 cursive)
-.build();
+%0A            .setCommonOptions(FileSystemMasterCommonPOptions.newBuilder()%0A                .setSyncIntervalMs(0).build())%0A            .build();%0A      %7D else %7B%0A        options = ListStatusPOptions.newBuilder().setRecursive(recursive).build();%0A      %7D
 %0A      m
@@ -3453,16 +3453,21 @@
 ata %5B-R%5D
+ %5B-F%5D
  %3Cpath%3E%22

Fix the semantic ambiguity of LoadMetadataCommand