/*
 * $Id$
 *
 * Copyright 1996-2008 Sun Microsystems, Inc.  All Rights Reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Sun designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Sun in the LICENSE file that accompanied this code.
 *
 * This code 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
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
 * CA 95054 USA or visit www.sun.com if you need additional information or
 * have any questions.
 */
package com.sun.javatest;

import java.io.File;

import com.sun.javatest.util.I18NResourceBundle;

/**
 * Filters tests based on a set of initial files or URLs.
 * Any test which does not begin with one of the supplied initial urls
 * is rejected.  This is the obvious way to select subsets of a test suite
 * based on the test suite hiearchy.
 * Comparisons of initial URLs vs. test URLs are done without respect to
 * case.
 *
 */
public class InitialUrlFilter extends TestFilter {
    /**
     * Create a filter based on the given files.  These file paths must be
     * relative to the testsuite root.  String matching against the paths
     * represented will be used to filter tests.  You may specify a path to a
     * "directory", a specific test, or to a filename which contains tests.
     *
     * @param initFiles Files which specify the tests to be accepted.  Null or
     * zero length arrays are accepted and result in accepts() always returning
     * true.
     */
    public InitialUrlFilter(File[] initFiles) {
        // preprocess
        if (initFiles == null || initFiles.length == 0)
            initUrls = null;
        else {
            initUrls = new String[initFiles.length];

            // validate, make path lower case, change path sep.
            for (int i = 0; i < initFiles.length; i++) {
                if (initFiles[i].isAbsolute())  // illegal, based on javadoc spec.
                    throw new IllegalArgumentException(initFiles[i].getPath());

                initUrls[i] = initFiles[i].getPath().toLowerCase();

                // fix path sep. IF needed
                if (File.separatorChar != '/')
                    initUrls[i] = initUrls[i].replace(File.separatorChar, '/');
            }   // for
        }
    }

    /**
     * Create a filter based on the given initial URLs.  These URLs must be
     * forward slash separated and relative to the testsuite root.  String
     * matching against the paths represented will be used to filter tests.
     * You may specify a path to a "directory", a specific test, or to a
     * filename which contains tests.
     *
     * @param initialUrls Paths which specify the tests to be accepted.  Null
     * or zero length arrays are accepted and result in accepts() always
     * returning true.
     */
    public InitialUrlFilter(String[] initialUrls) {
        // preprocess, make a copy
        if (initialUrls == null || initialUrls.length == 0)
            initUrls = null;
        else {
            initUrls = new String[initialUrls.length];
            //System.arraycopy(initialUrls, 0, initUrls, 0, initialUrls.length);
            for (int i = 0; i < initialUrls.length; i++) {
                initUrls[i] = initialUrls[i].toLowerCase();
            }   // for
        }
    }

    public boolean accepts(TestDescription td) {
        if (initUrls == null) // all urls being accepted
            return true;

        String testUrl = td.getRootRelativeURL().toLowerCase();

        // other parts of the code should ensure this is not null
        for (int i = 0; i < initUrls.length; i++) {
            String urlI = initUrls[i];
            if (isInitialUrlMatch(testUrl, initUrls[i]))
                return true;
        }   // for

        // no init. urls specified (initUrls.length == 0) OR
        // all init. urls processed
        return false;
    }

    /**
     * Find out if a given URL falls under a particular initial URL.
     * This effectively compares one incoming URL to one in a set of known
     * initial URLs.
     * @param toCheck The incoming name to check.  This might originate from a
     *        TestDescription being filtered.
     * @param compareTo The known initial URL to compare the previous parameter to.
     *        This would probably originate from a set of parameters.
     * @return True if the toCheck URL falls within the range specified by the compareTo
     *         URL.
     */
    public static boolean isInitialUrlMatch(String toCheck, String compareTo) {
        if (toCheck.equals(compareTo))  // direct match of test
            return true;
        // a startsWith match must end on one of the delimiter characters to
        // be a valid match.  the delim. can either be on the initial URL or
        // test URL
        // during a beginsWith:
        //    - is the last char of the initUrl a delimiter?
        //    - is the next char in the test URL a delimiter?
        else if (toCheck.startsWith(compareTo) &&
                 (isDelimiter(compareTo.charAt(compareTo.length()-1)) ||
                  isDelimiter(toCheck.charAt(compareTo.length())))) {
            return true;
        }
        else
            return false;
    }

    public String getName() {
        return i18n.getString("iurlFilter.name");
    }

    public String getDescription() {
        return i18n.getString("iurlFilter.description");
    }

    public String getReason() {
        return i18n.getString("iurlFilter.reason");
    }

    /**
     * Is this a delimiter that ends/begins a valid startsWith segment.
     */
    private static boolean isDelimiter(char c) {
        if (c == '/' || c == '#')
            return true;
        else
            return false;
    }

    private String[] initUrls;
    private static I18NResourceBundle i18n = I18NResourceBundle.getBundleForClass(ExcludeListFilter.class);
}
