/*
 * $Header: /home/cvspublic/jakarta-slide/proposals/tamino/src/util/org/apache/slide/util/nodeset/Glob.java,v 1.1 2004/03/25 16:18:12 juergen Exp $
 * $Revision: 1.1 $
 * $Date: 2004/03/25 16:18:12 $
 *
 * ====================================================================
 *
 * Copyright 1999-2004 The Apache Software Foundation.
 *
 * 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.apache.slide.util.nodeset;

import org.apache.oro.text.regex.MalformedPatternException;
import org.apache.oro.text.regex.Pattern;
import org.apache.oro.text.regex.PatternCompiler;
import org.apache.oro.text.regex.PatternMatcher;
import org.apache.oro.text.regex.Perl5Compiler;
import org.apache.oro.text.regex.Perl5Matcher;
import org.apache.slide.util.Strings;
import org.apache.slide.util.XAssertionFailed;

/**
 * File name patterns. Uses oro-matcher because we want to support jdk 1.3
 */
public class Glob {
    private static final PatternCompiler compiler;
    private static final PatternMatcher matcher;
    
    public static final Pattern STARSTAR;
    public static final Pattern STAR;

    static {
        compiler = new Perl5Compiler();
        matcher = new Perl5Matcher();
        
        STAR = doCompile(translate("*"), false /* same as true*/);
        // put () around to make both patterns !=
        STARSTAR = doCompile(translate("(*)"), false /* same as true */);
        if (STAR == STARSTAR) {
            throw new IllegalStateException();
        }
    }
    
    public static Pattern compile(String glob, boolean ignoreCase) {
        if (glob.equals("**")) {
            return STARSTAR;
        } else if (glob.equals("*")) {
            return STAR;
        } else {
            return doCompile(translate(glob), ignoreCase);
        }
    }

    public static boolean matches(Pattern pattern, String str) {
        return matcher.matches(str, pattern);
    }
    
    //--
    
    private static Pattern doCompile(String regexp, boolean ignoreCase) {
        try {
            return compiler.compile(regexp, ignoreCase? Perl5Compiler.CASE_INSENSITIVE_MASK : Perl5Compiler.DEFAULT_MASK);
        } catch (MalformedPatternException e) {
            throw new XAssertionFailed("malformed pattern '" + regexp + "': " + e.getMessage());
        }
    }
    
    /**
     * Translate a glob PATTERN to a regular expression.
     */
    private static String translate(String glob) {
        int i;
        int max;
        StringBuffer result;
        char c;
        int j;
        String stuff;

        max = glob.length();
        result = new StringBuffer();
        for (i = 0; i < max; ) {
            c = glob.charAt(i++);
            if (c == '*') {
                result.append(".*");
            } else if (c == '?') {
                result.append('.');
            } else if (c == '[') {
                j = i;
                if (j < max && glob.charAt(j) == '!') {
                    j++;
                }
                if (j < max && glob.charAt(j) == ']') {
                    j++;
                }
                while (j < max && glob.charAt(j) != ']') {
                    j++;
                }
                if (j >= max) {
                    result.append("\\[");
                } else {
                    stuff = glob.substring(i, j);
                    stuff = Strings.replace(stuff, "\\","\\\\");
                    i = j+1;
                    if (stuff.charAt(0) == '!') {
                        stuff = '^' + stuff.substring(1);
                    } else if (stuff.charAt(0) == '^') {
                        stuff = '\\' + stuff;
                    }
                    result.append('[');
                    result.append(stuff);
                    result.append(']');
                }
            } else {
                result.append(escape(c));
            }
        }
        result.append('$');
        return result.toString();
    }

    public static String escape(char c) {
        if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9')) {
            return "" + c;
        } else {
            return "\\" + c;
        }
    }
}
