Options.java

/*******************************************************************************
 * Copyright (c) 2004, 2013 Steve Flasby
 * All rights reserved.
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 * <ul>
 *     <li>Redistributions of source code must retain the above copyright notice,
 *         this list of conditions and the following disclaimer.</li>
 *     <li>Redistributions in binary form must reproduce the above copyright notice,
 *         this list of conditions and the following disclaimer in the documentation
 *         and/or other materials provided with the distribution.</li>
 * </ul>
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ******************************************************************************/
/*
 * Created on 16-Jul-2004
 *
 */
package org.flasby.cli;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import org.flasby.util.Message;

/**
 * @author flasbyst
 */
public class Options {
  ArrayList<Option> mOptions = new ArrayList<Option>();
  Set<String> mSwitchList = new HashSet<String>();
  final String mMlsPrefix;
  private final Message mMessages;

  public Options(Options copy) {
    this(copy.mMessages, copy.mMlsPrefix);
  }

  public Options(Message messages, String mlsPrefix) {
    if (mlsPrefix.endsWith(".")) {
      mMlsPrefix = mlsPrefix;
    } else {
      mMlsPrefix = mlsPrefix + ".";
    }
    mMessages = messages;
  }

  /**
   * returns a new MLS key with the qualifier appended to the prefix defined for this instance. This
   * is useful to quickly obtain NLS keys which are specific to this Options instance.
   *
   * @param qualifier
   * @return
   */
  public String getMlsKey(String qualifier) {
    return mMlsPrefix + qualifier;
  }

  /**
   * add a new Option to this option collection.
   *
   * @return the option to allow for command chaining.
   */
  public Option addOption(Option option) {
    if (mSwitchList.contains(option.getOpt()))
      throw new RuntimeException("you cant add the same option (" + option.getOpt() + ") twice.");
    mOptions.add(option);
    mSwitchList.add(option.getOpt());
    return option;
  }

  public OptionList addOption(OptionList option) {
    if (mSwitchList.contains(option.getOpt())) {
      throw new RuntimeException(
          "you cant add the same option twice: "
              + mSwitchList
              + "("
              + mSwitchList.size()
              + ") : '"
              + option.getOpt()
              + "'");
    }
    mOptions.add(option);
    mSwitchList.add(option.getOpt());
    return option;
  }

  public Flag addOption(Flag option) {
    if (mSwitchList.contains(option.getOpt()))
      throw new RuntimeException("you cant add the same option twice.");
    mOptions.add(option);
    mSwitchList.add(option.getOpt());
    return option;
  }

  /**
   * returns the options set on this collection of options.
   *
   * @return
   */
  public Option[] getOptions() {
    Option[] retval = new Option[mOptions.size()];
    mOptions.toArray(retval);
    return retval;
  }

  /**
   * returns a string suitable for showing to the user as a usage description.
   *
   * @return the usage string.
   */
  public String usage() {
    StringBuffer sb = new StringBuffer(CliMessage.MESSAGE.getMLS("org.flasby.cli.usage"));
    Iterator<Option> iter = mOptions.iterator();
    sb.append(" ").append(CliMessage.MESSAGE.getMLS("org.flasby.cli.application"));
    while (iter.hasNext()) {
      Option option = iter.next();
      sb.append(" ");
      if (!option.isMandatory()) sb.append(CliMessage.MESSAGE.getMLS("org.flasby.cli.<"));
      if (option.getOpt().length() > 0) {
        sb.append("-");
        sb.append(option.getOpt());
      }
      sb.append(" ").append(mMessages.getMLS(option.getDescriptionKey()));
      if (!option.isMandatory()) sb.append(CliMessage.MESSAGE.getMLS("org.flasby.cli.>"));
    }
    iter = mOptions.iterator();
    while (iter.hasNext()) {
      Option option = iter.next();
      sb.append(System.getProperty("line.separator")).append("\t");
      if (option.getOpt().length() > 0) sb.append("-");
      else sb.append("  ");
      sb.append(option.getOpt())
          .append(" ")
          .append(mMessages.getMLS(option.getDescriptionKey()))
          .append(" : ")
          .append(
              mMessages.getMLS(option.getDescriptionKey() + ".usage", option.getDefaultValue()));
    }
    return sb.toString();
  }

  /**
   * create an option which is not mandatory and has no defailt value.
   *
   * @param option
   * @param descriptionKey
   * @return
   */
  public Option create(final char option, final String descriptionKey) {
    return createOption(option, descriptionKey, null, false);
  }

  /**
   * create an option which is optional and has a default value.
   *
   * @param option
   * @param descriptionKey
   * @param defaultValue
   * @return
   */
  public Option create(final char option, final String descriptionKey, String defaultValue) {
    return createOption(option, descriptionKey, defaultValue, false);
  }

  /**
   * create a new option with control over if the option must be specified. This only makes sense if
   * te option is mandatory as you can create option ones usig other methods.
   *
   * @param option
   * @param descriptionKey
   * @param isMandatory
   * @return
   */
  public Option create(final char option, final String descriptionKey, final boolean isMandatory) {
    return createOption(option, descriptionKey, null, isMandatory);
  }

  /**
   * create a new option with full control over all possibilities. Notice that creating a mandatory
   * option with a default value is not very useful. Think about it.
   *
   * @param option
   * @param descriptionKey
   * @param defaultValue
   * @param isMandatory
   * @return
   */
  private Option createOption(
      final char option,
      final String descriptionKey,
      final String defaultValue,
      final boolean isMandatory) {
    return addOption(
        new Option() {
          /* (non-Javadoc)
           * @see org.flasby.cli.Option#isRequired()
           */
          @Override
          public boolean isMandatory() {
            return isMandatory;
          }

          @Override
          public String getDefaultValue() {
            return defaultValue;
          }

          /* (non-Javadoc)
           * @see org.flasby.cli.Option#getDescriptionKey()
           */
          @Override
          public String getDescriptionKey() {
            return mMlsPrefix + descriptionKey;
          }

          /* (non-Javadoc)
           * @see org.flasby.cli.Option#getOpt()
           */
          @Override
          public String getOpt() {
            return "" + option;
          }

          @Override
          public String toString() {
            return "opt:" + getOpt() + " key:" + getDescriptionKey();
          }
        });
  }

  /**
   * create a new option list. Option lists are used where an option can have multiple values.
   *
   * @param option
   * @param descriptionKey
   * @return
   */
  public OptionList createList(final char option, final String descriptionKey) {
    return createList(option, descriptionKey, false);
  }

  public OptionList createList(
      final char option, final String descriptionKey, final boolean isMandatory) {
    return addOption(
        new OptionList() {
          /* (non-Javadoc)
           * @see org.flasby.cli.Option#isRequired()
           */
          @Override
          public boolean isMandatory() {
            return isMandatory;
          }

          /* (non-Javadoc)
           * @see org.flasby.cli.Option#getDescriptionKey()
           */
          @Override
          public String getDescriptionKey() {
            return descriptionKey;
          }

          /* (non-Javadoc)
           * @see org.flasby.cli.Option#getOpt()
           */
          @Override
          public String getOpt() {
            return "" + option;
          }

          @Override
          public String toString() {
            return "opt:" + getOpt() + " key:" + getDescriptionKey();
          }

          @Override
          public String getDefaultValue() {
            return null;
          }
        });
  }

  public OptionList create(final String descriptionKey) {
    return create(descriptionKey, false, null);
  }

  public OptionList create(final String descriptionKey, final boolean isMandatory) {
    return create(descriptionKey, isMandatory, null);
  }

  public OptionList create(final String descriptionKey, String defaultValue) {
    return create(descriptionKey, false, defaultValue);
  }

  public OptionList create(final String descriptionKey, final boolean isMandatory, String defaultValue) {
    return addOption(
        new OptionList() {
          /* (non-Javadoc)
           * @see org.flasby.cli.Option#isRequired()
           */
          @Override
          public boolean isMandatory() {
            return isMandatory;
          }

          /* (non-Javadoc)
           * @see org.flasby.cli.Option#getDescriptionKey()
           */
          @Override
          public String getDescriptionKey() {
            return mMlsPrefix + descriptionKey;
          }

          /* (non-Javadoc)
           * @see org.flasby.cli.Option#getOpt()
           */
          @Override
          public String getOpt() {
            return "";
          }

          @Override
          public String toString() {
            return "opt:" + getOpt() + " key:" + getDescriptionKey();
          }

          @Override
          public String getDefaultValue() {
            return defaultValue;
          }
        });
  }

  public Flag createFlag(final char flag, final String descriptionKey) {
    return addOption(
        new Flag() {
          @Override
          public boolean isMandatory() {
            return false;
          }

          @Override
          public String getDefaultValue() {
            return null;
          }

          @Override
          public String getDescriptionKey() {
            return mMlsPrefix + descriptionKey;
          }

          @Override
          public String getOpt() {
            return "" + flag;
          }

          @Override
          public String toString() {
            return "flag:" + getOpt() + " key:" + getDescriptionKey();
          }
        });
  }

  public Message getMessageBundle() {
    return mMessages;
  }

  @Override
  public String toString() {
    return "Options [mOptions=" + mOptions + "]";
  }
}