package com.jscape.util.cli.ext;

import static com.jscape.util.Parameters.assertNotNull;

/**
 * Represents a single command line option.
 *
 * @author Alex Usun
 */
public class SingleOption
        implements Option {

    private final String name;
    private final boolean required;
    private boolean present;


    public SingleOption(String name, boolean required, boolean present) {
        assertNotNull(name);
        this.name = name;

        this.required = required;
        this.present = present;
    }

    /**
     * Creates a new option instance.
     *
     * @param name     an option name
     * @param required an option requirement flag
     */
    public SingleOption(String name, boolean required) {
        this(name, required, false);
    }

    public SingleOption(SingleOption that) {
        this(that.name, that.required, that.present);
    }

    /**
     * Returns the option name.
     *
     * @return the option name
     */
    public String name() {
        return this.name;
    }

    /**
     * Returns the option requirement flag.
     *
     * @return <code>true</code> if option is required; <code>false</code> otherwise
     */
    public boolean required() {
        return this.required;
    }

    public boolean present() {
        return this.present;
    }

    public void reset() {
        this.present = false;
    }

    /**
     * Sets the option presence.
     */
    public void setPresent() {
        this.present = true;
    }

    public SingleOption copy() {
        return new SingleOption(this);
    }

    @Override
    public String toString() {
        return "SingleOption {"
                + "name='" + this.name + '\''
                + ", required=" + this.required
                + ", present=" + this.present
                + '}';
    }

    /**
     * A single option parser.
     */
    public static class Format
            implements OptionFormat {

        public void parse(Option option, Arguments arguments)
                throws InvalidArgumentsException {
            SingleOption targetOption = (SingleOption) option;
            String optionName = targetOption.name();

            for (Argument argument : arguments) {
                if (!argument.parsed() && optionName.equals(argument.value())) {
                    targetOption.setPresent();
                    argument.setParsed();

                    return;
                }
            }

            assertRequiredOptionFound(targetOption);
        }

        private void assertRequiredOptionFound(SingleOption option)
                throws InvalidArgumentsException {
            if (option.required()) {
                throw new InvalidArgumentsException(String.format("Required option [%s] not found.", option.name()));
            }
        }
    }
}
