001/*
002 * Copyright (C) 2012 eXo Platform SAS.
003 *
004 * This is free software; you can redistribute it and/or modify it
005 * under the terms of the GNU Lesser General Public License as
006 * published by the Free Software Foundation; either version 2.1 of
007 * the License, or (at your option) any later version.
008 *
009 * This software is distributed in the hope that it will be useful,
010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012 * Lesser General Public License for more details.
013 *
014 * You should have received a copy of the GNU Lesser General Public
015 * License along with this software; if not, write to the Free
016 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
017 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
018 */
019package org.crsh.lang.impl.groovy.closure;
020
021import org.crsh.shell.impl.command.spi.Command;
022import org.crsh.shell.impl.command.spi.CommandException;
023import org.crsh.shell.impl.command.spi.CommandInvoker;
024
025import java.util.ArrayList;
026import java.util.HashMap;
027import java.util.Iterator;
028import java.util.List;
029import java.util.Map;
030
031/** @author Julien Viet */
032class CommandElement extends PipeLineElement {
033
034  /** . */
035  final String commandName;
036
037  /** . */
038  final Command<?> command;
039
040  /** . */
041  final Map<String, Object> options;
042
043  /** . */
044  final String subordinate;
045
046  /** . */
047  final Map<String, Object> subordinateOptions;
048
049  /** . */
050  final List<Object> args;
051
052  public CommandElement(String commandName, Command<?> command, Map<String, Object> options) {
053    this.commandName = commandName;
054    this.command = command;
055    this.options = options;
056    this.subordinate = null;
057    this.subordinateOptions = null;
058    this.args = null;
059  }
060
061  public CommandElement subordinate(String name) {
062    return new CommandElement(
063        this.commandName + "." + name,
064        this.command,
065        this.options,
066        name,
067        this.subordinateOptions,
068        this.args);
069  }
070
071  public CommandElement merge(Map<String, ?> options, List<?> arguments) {
072
073    // We merge options
074    Map<String, Object> nextOptions;
075    if (subordinate == null) {
076      nextOptions = this.options;
077    } else {
078      nextOptions = this.subordinateOptions;
079    }
080    if (options != null && options.size() > 0) {
081      if (nextOptions == null) {
082        nextOptions = new HashMap<String, Object>();
083      } else {
084        nextOptions = new HashMap<String, Object>(options);
085      }
086      for (Map.Entry<?, ?> arg : options.entrySet()) {
087        nextOptions.put(arg.getKey().toString(), arg.getValue());
088      }
089    }
090
091    // We merge arguments
092    List<Object> nextArgs;
093    if (arguments != null) {
094      nextArgs = new ArrayList<Object>();
095      if (this.args != null) {
096        nextArgs.addAll(this.args);
097      }
098      nextArgs.addAll(arguments);
099    } else {
100      nextArgs = this.args;
101    }
102
103    //
104    if (subordinate == null) {
105      return new CommandElement(this.commandName, this.command, nextOptions, null, null, nextArgs);
106    } else {
107      return new CommandElement(this.commandName, this.command, this.options, subordinate, nextOptions, nextArgs);
108    }
109  }
110
111  private CommandElement(String commandName, Command<?> command, Map<String, Object> options, String subordinate, Map<String, Object> subordinateOptions, List<Object> args) {
112    this.commandName = commandName;
113    this.command = command;
114    this.options = options;
115    this.subordinate = subordinate;
116    this.subordinateOptions = subordinateOptions;
117    this.args = args;
118  }
119
120  @Override
121  CommandInvoker create() throws CommandException {
122    return command.resolveCommand(options, subordinate, subordinateOptions, args).getInvoker();
123  }
124
125  private void format(Object o, StringBuilder buffer) {
126    if (o instanceof String) {
127      buffer.append('"').append(o).append('"');
128    } else if (o instanceof Boolean || o instanceof Number) {
129      buffer.append(o);
130    } else {
131      buffer.append('<').append(o).append('>');
132    }
133  }
134
135  void toString(StringBuilder buffer) {
136    buffer.append(commandName);
137    boolean hasOptions = subordinateOptions != null && subordinateOptions.size() > 0;
138    boolean hasArguments = args != null && args.size() > 0;
139    if (hasOptions || hasArguments) {
140      buffer.append(" {");
141      if (hasOptions) {
142        for (Iterator<Map.Entry<String, Object>> i = subordinateOptions.entrySet().iterator();i.hasNext();) {
143          Map.Entry<String, Object> option = i.next();
144          buffer.append(' ').append(option.getKey()).append('=');
145          format(option.getValue(), buffer);
146          if (i.hasNext()) {
147            buffer.append(";");
148          }
149        }
150        if (hasArguments) {
151          buffer.append(";");
152        }
153      }
154      if (hasArguments) {
155        buffer.append(" [");
156        for (Iterator<Object> i = args.iterator();i.hasNext();) {
157          Object arg = i.next();
158          format(arg, buffer);
159          if (i.hasNext()) {
160            buffer.append(", ");
161          }
162        }
163        buffer.append("]");
164      }
165      buffer.append(" }");
166    }
167  }
168}