/*
 * Copyright 1999-2006 University of Chicago
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.globus.ftp;

import java.util.List;
import java.util.ArrayList;
import java.util.StringTokenizer;

/**
   Represents features supported by server (as returned by FEAT command).
   Use the static members of this class to refer to well known feature names.
   Example: check if the server supports PARALLEL feature:
   <pre>
   FeatureList fl = new FeatureList(client.getFeatureList());
   if (fl.contains(FeatureList.PARALLEL)) {
       ...
   }
   </pre>
 **/

public class FeatureList {

    /**
     * RFC 2389 specified the following syntax for FEAT responce
     * <pre>
     * feat-response   = error-response / no-features / feature-listing
     *  no-features     = "211" SP *TCHAR CRLF
     *  feature-listing = "211-" *TCHAR CRLF
     *                    1*( SP feature CRLF )
     *                    "211 End" CRLF
     *  feature         = feature-label [ SP feature-parms ]
     *  feature-label   = 1*VCHAR
     *  feature-parms   = 1*TCHAR
     * </pre>
     *  Feature class represence each individual feature and contain two fields
     *  required label and optional parms
     *
     */
    public static final class Feature {

        private final String label;

        private final String parms;

        private Feature (String label) {

        if(label == null ) {
            throw new NullPointerException("label is null");
        }

        this.label = label;
        this.parms = null;

        }

        private Feature (String label, String parms) {

        if(label == null ) {
            throw new NullPointerException("label is null");
        }

        this.label = label;
        this.parms = parms;

        }

        /**
         * @return the name
         */
        public String getLabel() {

        return label;

        }

        /**
         * @return the qualifiers, null if no qualifiers
         */
        public String getParms() {

        return parms;

        }

        @Override
        public boolean equals(Object obj) {

        if( !(obj instanceof Feature)) {
            return false;
        }

        Feature aFeature = (Feature) obj;

        if( !label.equals(aFeature.label) ) {
            return false;
        }

        if( parms == null ) {
            return aFeature.parms == null;
        }

        return parms.equals( aFeature.parms);
       }
    }

    // well known labels
    public static final String SIZE = "SIZE";
    public static final String MDTM = "MDTM";
    public static final String PARALLEL = "PARALLEL";
    public static final String ESTO = "ESTO";
    public static final String ERET = "ERET";
    public static final String SBUF = "SBUF";
    public static final String ABUF = "ABUF";
    public static final String DCAU = "DCAU";
    public static final String PIPE = "PIPE";
    public static final String MODEX = "MODEX";
    public static final String GETPUT = "GETPUT";
    public static final String CKSUM =  "CKSUM";

    protected final List<Feature> features = new ArrayList();

    public FeatureList(String featReplyMsg) {

	StringTokenizer responseTokenizer
	    = new StringTokenizer(featReplyMsg,
				  System.getProperty("line.separator"));

	// ignore the first part of the message
	if (responseTokenizer.hasMoreElements()) {
	    responseTokenizer.nextToken();
	}

	while ( responseTokenizer.hasMoreElements() ) {

	    String line = (String) responseTokenizer.nextElement();
	    line = line.trim().toUpperCase();
	    if ( line.startsWith( "211 END" ) ) {
            break;
        }
        String[] splitFeature = line.split(" ");

        if( splitFeature.length ==2) {
            features.add(new Feature(splitFeature[0], splitFeature[1]));
        } else {
            features.add(new Feature(line));
        }

	}
    }

    public boolean contains(String label) {

	if (label == null) {
	    throw new IllegalArgumentException("label is null");
	}
        //split argument using white space.
        String[] tokens = label.split(" ",2);
        if(tokens.length <1) {
	    throw new IllegalArgumentException("label is empty");
        }
        label = tokens[0].toUpperCase();
        String parms = null;
        if(tokens.length >1) {
            parms = tokens[1];
        }

        for( Feature feature:features ) {
            if(feature.getLabel().equals(label)) {
                if (parms == null) {
                    //if parms are not specified as a part of the argument
                    // string, we compare labels only
                    return true;
                } else {
                    //if parms are specified, we compare them as well
                    Feature argFeature = new Feature(label, parms);
                    if(argFeature.equals(feature)) {
                        return true;
                    }
                }
            }
        }

        return false;

    }

    /**
     * Get all features that have label equal to the argument
     * Note that  RFC 2389 does not require a feature with a
     * given label to appear only once
     * @param label
     * @return List of found features with given label in the same order
     * as they were given to us by the server
     */
    public List<Feature> getFeature(String label) {

	if (label == null) {
	    throw new IllegalArgumentException("feature label is null");
	}

    label = label.toUpperCase();
    List<Feature> foundFeatures = new ArrayList();
    for( Feature feature:features ) {
        if(feature.getLabel().equals(label)) {
            foundFeatures.add(feature);
        }
    }

    return foundFeatures;

    }
}
