/*
 Copyright 2004-2008 Paul R. Holser, Jr.  All rights reserved.
 Licensed under the Academic Free License version 3.0
 */

package joptsimple;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

/**
 * <p>Describes options that an option parser recognizes.</p>
 *
 * @since 1.0
 * @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a>
 * @version $Id: OptionSpec.java,v 1.3 2008/04/10 19:41:55 pholser Exp $
 */
abstract class OptionSpec {
    private final List options = new ArrayList();
    private final String description;

    protected OptionSpec( String option ) {
        this( Collections.singletonList( option ), "" );
    }

    protected OptionSpec( List options, String description ) {
        arrangeOptions( options );
        this.description = description;
    }

    List options() {
        return options;
    }

    String description() {
        return description;
    }

    abstract void handleOption( OptionParser parser, ArgumentList arguments,
        OptionSet detectedOptions, String detectedArgument );

    abstract boolean acceptsArguments();

    abstract boolean requiresArgument();

    abstract void accept( OptionSpecVisitor visitor );

    public boolean equals( Object that ) {
        if ( this == that )
            return true;

        if ( that == null || !getClass().equals( that.getClass() ) )
            return false;

        OptionSpec other = (OptionSpec) that;
        return options.equals( other.options );
    }

    public int hashCode() {
        return options.hashCode();
    }

    private void arrangeOptions( List options ) {
        if ( options.size() == 1 ) {
            this.options.addAll( options );
            return;
        }

        List shortOptions = new ArrayList();
        List longOptions = new ArrayList();

        for ( Iterator iter = options.iterator(); iter.hasNext(); ) {
            String next = (String) iter.next();
            if ( next.length() == 1 )
                shortOptions.add( next );
            else
                longOptions.add( next );
        }

        Collections.sort( shortOptions );
        Collections.sort( longOptions );

        this.options.addAll( shortOptions );
        this.options.addAll( longOptions );
    }
}
