/*
 * 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.shell.command;

import alluxio.AlluxioURI;
import alluxio.client.file.FileSystem;
import alluxio.client.file.options.MountOptions;
import alluxio.exception.AlluxioException;

import com.google.common.base.Preconditions;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.annotation.concurrent.ThreadSafe;

/**
 * Mounts a UFS path onto an Alluxio path.
 */
@ThreadSafe
public final class MountCommand extends AbstractShellCommand {
  private static final Pattern OPTION_PATTERN = Pattern.compile("(.*)=(.*)");

  private static final Option READONLY_OPTION =
      Option.builder()
          .longOpt("readonly")
          .required(false)
          .hasArg(false)
          .desc("mount point is readonly in Alluxio")
          .build();
  private static final Option SHARED_OPTION =
      Option.builder()
          .longOpt("shared")
          .required(false)
          .hasArg(false)
          .desc("mount point is shared")
          .build();
  private static final Option OPTION_OPTION =
      Option.builder()
          .longOpt("option")
          .argName("key=value")
          .required(false)
          .hasArg(true)
          .desc("options associated with this mount point")
          .build();
  // TODO(gpang): Investigate property=value style of cmdline options. They didn't seem to
  // support spaces in values.
  private static final Option PROPERTY_FILE_OPTION =
      Option.builder("P")
          .required(false)
          .numberOfArgs(1)
          .desc("properties file name")
          .build();

  /**
   * @param fs the filesystem of Alluxio
   */
  public MountCommand(FileSystem fs) {
    super(fs);
  }

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

  @Override
  protected int getNumOfArgs() {
    return 2;
  }

  @Override
  protected Options getOptions() {
    return new Options().addOption(PROPERTY_FILE_OPTION).addOption(READONLY_OPTION)
        .addOption(SHARED_OPTION).addOption(OPTION_OPTION);
  }

  @Override
  public int run(CommandLine cl) throws AlluxioException, IOException {
    String[] args = cl.getArgs();
    AlluxioURI alluxioPath = new AlluxioURI(args[0]);
    AlluxioURI ufsPath = new AlluxioURI(args[1]);
    MountOptions options = MountOptions.defaults();

    String propertyFile = cl.getOptionValue('P');
    if (propertyFile != null) {
      Properties cmdProps = new Properties();
      try (InputStream inStream = new FileInputStream(propertyFile)) {
        cmdProps.load(inStream);
      } catch (IOException e) {
        throw new IOException("Unable to load property file: " + propertyFile);
      }

      if (!cmdProps.isEmpty()) {
        // Use the properties from the properties file for the mount options.
        Map<String, String> properties = new HashMap<>();
        for (Map.Entry<Object, Object> entry : cmdProps.entrySet()) {
          properties.put(entry.getKey().toString(), entry.getValue().toString());
        }
        options.setProperties(properties);
        System.out.println("Using properties from file: " + propertyFile);
      }
    }

    if (cl.hasOption("readonly")) {
      options.setReadOnly(true);
    }

    if (cl.hasOption("shared")) {
      options.setShared(true);
    }

    if (cl.hasOption("option")) {
      Map<String, String> properties = new HashMap<>();
      String[] optionValues = cl.getOptionValues("option");
      for (String option : optionValues) {
        Matcher matcher = OPTION_PATTERN.matcher(option);
        Preconditions.checkArgument(matcher.matches(), "Unrecognized property %s", option);
        String key = matcher.group(1);
        String value = matcher.group(2);
        properties.put(key, value);
      }
      options.setProperties(properties);
    }

    mFileSystem.mount(alluxioPath, ufsPath, options);
    System.out.println("Mounted " + ufsPath + " at " + alluxioPath);
    return 0;
  }

  @Override
  public String getUsage() {
    return "mount [--readonly] [--shared] [--option <key=val>] [-P <path>] <alluxioPath> <ufsURI>";
  }

  @Override
  public String getDescription() {
    return "Mounts a UFS path onto an Alluxio path.";
  }
}

@@ -883,79 +883,19 @@
 .io.
-FileInputStream;%0Aimport java.io.IOException;%0Aimport java.io.InputStream
+IOException
 ;%0Aim
@@ -944,37 +944,8 @@
 ap;%0A
-import java.util.Properties;%0A
 impo
@@ -1799,40 +1799,8 @@
 n%22)%0A
-          .argName(%22key=value%22)%0A
     
@@ -1846,16 +1846,48 @@
 g(true)%0A
+          .argName(%22key=value%22)%0A
         
@@ -1961,323 +1961,8 @@
 d();
-%0A  // TODO(gpang): Investigate property=value style of cmdline options. They didn't seem to%0A  // support spaces in values.%0A  private static final Option PROPERTY_FILE_OPTION =%0A      Option.builder(%22P%22)%0A          .required(false)%0A          .numberOfArgs(1)%0A          .desc(%22properties file name%22)%0A          .build();
 %0A%0A  
@@ -2293,21 +2293,16 @@
 ion(
-PROPERTY_FILE
+READONLY
 _OPT
@@ -2312,32 +2312,30 @@
 ).addOption(
-READONLY
+SHARED
 _OPTION)%0A   
@@ -2343,33 +2343,8 @@
     
-.addOption(SHARED_OPTION)
 .add
@@ -2654,998 +2654,185 @@
     
-String propertyFile = cl.getOptionValue('P');%0A    if (propertyFile != null) %7B%0A      Properties cmdProps = new Properties();%0A      try (InputStream inStream = new FileInputStream(propertyFile)) %7B%0A        cmdProps.load(inStream);%0A      %7D catch (IOException e) %7B%0A        throw new IOException(%22Unable to load property file: %22 + propertyFile);%0A      %7D%0A%0A      if (!cmdProps.isEmpty()) %7B%0A        // Use the properties from the properties file for the mount options.%0A        Map%3CString, String%3E properties = new HashMap%3C%3E();%0A        for (Map.Entry%3CObject, Object%3E entry : cmdProps.entrySet()) %7B%0A          properties.put(entry.getKey().toString(), entry.getValue().toString());%0A        %7D%0A        options.setProperties(properties);%0A        System.out.println(%22Using properties from file: %22 + propertyFile);%0A      %7D%0A    %7D%0A%0A    if (cl.hasOption(%22readonly%22)) %7B%0A      options.setReadOnly(true);%0A    %7D%0A%0A    if (cl.hasOption(%22shared%22)) %7B%0A      options.setShared(true);%0A    %7D%0A%0A    if (cl.hasOption(%22option%22
+options.setReadOnly(cl.hasOption(READONLY_OPTION.getLongOpt()));%0A    options.setShared(cl.hasOption(SHARED_OPTION.getLongOpt()));%0A    if (cl.hasOption(OPTION_OPTION.getLongOpt()
 )) %7B
@@ -3492,24 +3492,24 @@
 etUsage() %7B%0A
+
     return %22
@@ -3562,20 +3562,8 @@
 al%3E%5D
- %5B-P %3Cpath%3E%5D
  %3Cal

Remove unused -P option since we have --option now