/*
* Copyright (c) 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017 David Berkman
*
* This file is part of the SmallMind Code Project.
*
* The SmallMind Code Project is free software, you can redistribute
* it and/or modify it under either, at your discretion...
*
* 1) The terms of GNU Affero General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* ...or...
*
* 2) The terms of the Apache License, Version 2.0.
*
* The SmallMind Code Project is distributed in the hope that it will
* be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License or Apache License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* and the Apache License along with the SmallMind Code Project. If not, see
* <http://www.gnu.org/licenses/> or <http://www.apache.org/licenses/LICENSE-2.0>.
*
* Additional permission under the GNU Affero GPL version 3 section 7
* ------------------------------------------------------------------
* If you modify this Program, or any covered work, by linking or
* combining it with other code, such other code is not for that reason
* alone subject to any of the requirements of the GNU Affero GPL
* version 3.
*/
package org.smallmind.nutsnbolts.command.template;
import java.io.InputStream;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import org.smallmind.nutsnbolts.command.CommandLineException;
import org.smallmind.nutsnbolts.command.sax.OptionsDocumentExtender;
import org.smallmind.nutsnbolts.lang.UnknownSwitchCaseException;
import org.smallmind.nutsnbolts.xml.SmallMindProtocolResolver;
import org.smallmind.nutsnbolts.xml.XMLEntityResolver;
import org.smallmind.nutsnbolts.xml.sax.ExtensibleSAXParser;
import org.xml.sax.InputSource;
public class Template {
private static final XMLEntityResolver SMALL_MIND_ENTITY_RESOLVER = new XMLEntityResolver(SmallMindProtocolResolver.getInstance());
private LinkedList<Option> optionList;
private HashSet<Option> optionSet = new HashSet<>();
private String shortName;
public static Template createTemplate (Class entryClass)
throws CommandLineException {
Template template;
OptionsDocumentExtender optionsDocumentExtender;
InputStream optionsInputStream;
template = new Template(entryClass);
optionsDocumentExtender = new OptionsDocumentExtender(template);
try {
if ((optionsInputStream = Template.class.getClassLoader().getResourceAsStream(entryClass.getCanonicalName().replace('.', '/') + ".arguments.xml")) == null) {
throw new CommandLineException("No arguments file found matching Class(%s)", entryClass.getCanonicalName());
}
ExtensibleSAXParser.parse(optionsDocumentExtender, new InputSource(optionsInputStream), SMALL_MIND_ENTITY_RESOLVER);
} catch (Exception exception) {
throw new CommandLineException(exception);
}
return template;
}
public Template (Class entryClass) {
shortName = entryClass.getSimpleName();
}
public String getShortName () {
return shortName;
}
public synchronized List<Option> getRootOptionList () {
return Collections.unmodifiableList(optionList);
}
public synchronized Set<Option> getOptionSet () {
return Collections.unmodifiableSet(optionSet);
}
public synchronized void setOptionList (LinkedList<Option> optionList)
throws CommandLineException {
this.optionList = optionList;
addOptions(optionList);
}
public synchronized void addOptions (LinkedList<Option> optionList)
throws CommandLineException {
for (Option option : optionList) {
if (((option.getName() == null) || option.getName().isEmpty()) && (option.getFlag() == null)) {
throw new CommandLineException("All options must have either their 'name' or 'flag' set");
}
for (Option heldOption : optionSet) {
if ((option.getName() != null) && (!option.getName().isEmpty())) {
if (option.getName().equals(heldOption.getName())) {
throw new CommandLineException("All options must have a unique 'name', '%s' has been used", option.getName());
}
}
if (option.getFlag() != null) {
if (option.getFlag().equals(heldOption.getFlag())) {
throw new CommandLineException("All options must have a unique 'flag', '%s' has been used", option.getFlag().toString());
}
}
}
optionSet.add(option);
}
}
public synchronized String toString () {
StringBuilder lineBuilder = new StringBuilder();
stringifyOptions(lineBuilder, optionList);
return lineBuilder.toString();
}
private void stringifyOptions (StringBuilder lineBuilder, List<Option> optionList) {
boolean first = true;
lineBuilder.append('{');
for (Option option : optionList) {
boolean named = false;
if (!first) {
lineBuilder.append(' ');
}
lineBuilder.append(option.isRequired() ? '[' : '<');
if ((option.getName() != null) && (!option.getName().isEmpty())) {
lineBuilder.append("--").append(option.getName());
named = true;
}
if (option.getFlag() != null) {
if (named) {
lineBuilder.append(", ");
}
lineBuilder.append('-').append(option.getFlag());
}
switch (option.getArgument().getType()) {
case NONE:
break;
case SINGLE:
lineBuilder.append(' ').append(((SingleArgument)option.getArgument()).getDescription());
break;
case LIST:
lineBuilder.append(' ').append(((ListArgument)option.getArgument()).getDescription()).append("...");
break;
case ENUMERATED:
lineBuilder.append(" (");
for (int index = 0; index < ((EnumeratedArgument)option.getArgument()).getValues().length; index++) {
if (index > 0) {
lineBuilder.append('|');
}
lineBuilder.append(((EnumeratedArgument)option.getArgument()).getValues()[index]);
}
lineBuilder.append(')');
default:
throw new UnknownSwitchCaseException(option.getArgument().getType().name());
}
if ((option.getOptionList() != null) && (!option.getOptionList().isEmpty())) {
lineBuilder.append(' ');
stringifyOptions(lineBuilder, option.getOptionList());
}
lineBuilder.append(option.isRequired() ? ']' : '>');
first = false;
}
lineBuilder.append('}');
}
}