/*
 * Copyright (C) 2016 Christian Stein
 *
 * 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 de.sormuras.beethoven.script;

import de.sormuras.beethoven.Listing;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.IntStream;

public class Script {

  public static String eval(String source, Object... args) {
    return new Script(source).eval(new Listing(), args).toString();
  }

  public static String eval(String source, Map<String, Object> map) {
    return new Script(source).eval(new Listing(), map).toString();
  }

  private final String source;
  private final List<Command> commands;

  Script(String source) {
    this(source, new Parser().parse(source));
  }

  Script(String source, List<Command> commands) {
    this.source = source;
    this.commands = commands;
  }

  public Listing eval(Listing listing, Object... args) {
    Map<String, Object> map = new LinkedHashMap<>();
    IntStream.range(0, args.length).forEach(i -> map.put(Integer.toString(i), args[i]));
    return eval(listing, map);
  }

  public Listing eval(Listing listing, Map<String, Object> map) {
    int argumentConsumingCommandCounter = 0;
    for (Command command : commands) {
      Object argument = null;
      if (command.selectArgument()) {
        String key = command.selector;
        if (key == null) {
          key = String.valueOf(argumentConsumingCommandCounter++);
        }
        argument = map.get(key);
      }
      command.execute(listing, argument);
    }
    return listing;
  }
}

@@ -675,76 +675,223 @@
 ort 
-java.util.LinkedHashMap;%0Aimport java.util.List;%0Aimport java.util.Map
+de.sormuras.beethoven.Name;%0Aimport java.lang.reflect.Method;%0Aimport java.util.LinkedHashMap;%0Aimport java.util.List;%0Aimport java.util.Map;%0Aimport java.util.Objects;%0Aimport java.util.Optional;%0Aimport java.util.Scanner
 ;%0Aim
@@ -2130,69 +2130,1073 @@
     
-command.execute(listing, argument);%0A    %7D%0A    return listing;
+//      Optional%3CObject%3E result = reflect(command.snippet, argument);%0A      //      if (result.isPresent()) %7B%0A      //        return listing.addAny(result.get());%0A      //      %7D%0A      command.execute(listing, argument);%0A    %7D%0A    return listing;%0A  %7D%0A%0A  // convert unknown snippet to chained method call sequence%0A  protected Optional%3CObject%3E reflect(String snippet, Object argument) %7B%0A    Objects.requireNonNull(argument, %22argument must not be null%22);%0A    try (Scanner scanner = new Scanner(snippet)) %7B%0A      scanner.useDelimiter(Name.DOT);%0A      while (scanner.hasNext()) %7B%0A        String name = scanner.next();%0A        Method method;%0A        try %7B%0A          method = argument.getClass().getMethod(name);%0A        %7D catch (NoSuchMethodException e) %7B%0A          name = %22get%22 + name.substring(0, 1).toUpperCase() + name.substring(1);%0A          method = argument.getClass().getMethod(name);%0A        %7D%0A        argument = method.invoke(argument);%0A      %7D%0A      return Optional.ofNullable(argument);%0A    %7D catch (Exception exception) %7B%0A      return Optional.empty();%0A    %7D
 %0A  %7D

Add reflection support - not used, yet.