/*
 * Copyright (c) 2009-present the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.planet57.gshell.commands.standard;

import java.util.List;
import java.util.Properties;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;

import com.planet57.gshell.command.Command;
import com.planet57.gshell.command.CommandContext;
import com.planet57.gshell.util.io.IO;
import com.planet57.gshell.command.CommandActionSupport;
import com.planet57.gshell.util.cli2.Argument;
import com.planet57.gshell.util.cli2.Option;
import com.planet57.gshell.util.jline.Complete;
import com.planet57.gshell.variables.Variables;
import com.planet57.gshell.util.i18n.I18N;
import com.planet57.gshell.util.i18n.MessageBundle;

import static com.google.common.base.Preconditions.checkArgument;

/**
 * Set a variable or property.
 *
 * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
 * @since 2.5
 */
@Command(name = "set", description = "Set a variable or property")
public class SetAction
    extends CommandActionSupport
{
  private interface Messages
    extends MessageBundle
  {
    @DefaultMessage("Missing required argument: %s")
    String missingArgument(final String name);
  }

  private static final Messages messages = I18N.create(Messages.class);

  enum Mode
  {
    VARIABLE,
    PROPERTY
  }

  @Option(name = "m", longName = "mode", description = "Set mode", token = "MODE")
  private Mode mode = Mode.VARIABLE;

  @Option(name = "v", longName = "verbose", description = "Enable verbose output")
  private boolean verbose;

  @Nullable
  @Argument(index = 0, description = "Variable or property name", token = "NAME")
  private String name;

  @Nullable
  @Argument(index = 1, description = "Variable or property value or expression to evaluate", token = "VALUE")
  @Complete("variable-name")
  private List<String> values;

  @Override
  public Object execute(@Nonnull final CommandContext context) throws Exception {
    if (name == null) {
      return displayList(context);
    }
    checkArgument(values != null, messages.missingArgument("VALUE"));

    String value = String.join(" ", values);

    switch (mode) {
      case PROPERTY:
        log.debug("Setting system property: {}={}", name, value);
        System.setProperty(name, value);
        break;

      case VARIABLE:
        Variables vars = context.getVariables();
        log.debug("Setting variable: {}={}", name, value);
        vars.set(name, value);
        break;
    }

    return null;
  }

  private Object displayList(final CommandContext context) throws Exception {
    IO io = context.getIo();

    // using RAW io.stream.out to avoid any ANSI encoding

    switch (mode) {
      case PROPERTY: {
        Properties props = System.getProperties();

        for (Object o : props.keySet()) {
          String name = (String) o;
          String value = props.getProperty(name);
          io.streams.out.printf("%s='%s'%n", name, value);
        }
        break;
      }

      case VARIABLE: {
        Variables variables = context.getVariables();
        for (String name : variables.names()) {
          Object value = variables.get(name);
          io.streams.out.printf("%s='%s'", name, value);

          // When --verbose include the class details of the values
          if (verbose && value != null) {
            io.streams.out.printf(" (%s)", value.getClass());
          }

          io.streams.out.println();
        }
        break;
      }
    }

    // force RAW stream to flush
    io.streams.out.flush();

    return null;
  }
}

@@ -664,16 +664,44 @@
 ndard;%0A%0A
+import java.io.PrintStream;%0A
 import j
@@ -3227,16 +3227,54 @@
 encoding
+%0A    PrintStream out = io.streams.out;
 %0A%0A    sw
@@ -3361,25 +3361,24 @@
 ties();%0A
-%0A
         
 for (Obj
@@ -3373,159 +3373,59 @@
     
-for (Object o : props.keySet()) %7B%0A          String name = (String) o;%0A          String value = props.getProperty(name);%0A          io.streams.out.printf
+props.forEach((name, value) -%3E%0A          out.format
 (%22%25s
@@ -3438,33 +3438,32 @@
 n%22, name, value)
-;
 %0A        %7D%0A     
@@ -3447,33 +3447,34 @@
  value)%0A        
-%7D
+);
 %0A        break;%0A
@@ -3517,179 +3517,86 @@
     
-Variables variables = context.getVariables();%0A        for (String name : variables.names()) %7B%0A          Object value = variables.get(name);%0A          io.streams.out.printf
+context.getVariables().asMap().forEach((name, value) -%3E %7B%0A          out.format
 (%22%25s
@@ -3744,29 +3744,18 @@
     
-io.streams.out.printf
+out.format
 (%22 (
@@ -3798,35 +3798,24 @@
 %0A%0A          
-io.streams.
 out.println(
@@ -3822,24 +3822,26 @@
 );%0A        %7D
+);
 %0A        bre
@@ -3896,27 +3896,16 @@
 ush%0A    
-io.streams.
 out.flus

tidy set impl