/*
 * $Header: /home/cvspublic/jakarta-slide/proposals/tamino/src/util/org/apache/slide/util/XUri.java,v 1.4 2004/12/15 10:38:27 pnever Exp $
 * $Revision: 1.4 $
 * $Date: 2004/12/15 10:38:27 $
 *
 * ====================================================================
 *
 * 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;

import java.util.Collection;

/**
 ** Does not distingush absolute and relative uri's. Immutable.
 **
 ** @author    michael.hartmeier@softwareag.com
 ** @version   $Revision: 1.4 $
 **/
public class XUri {
    public static final String HTTP_PREFIX                      = "http://";
    
    public static final String XML_SUFF = ".xml"; // TODO: move somewhere else
    public static final String SEP = "/";

    /**
     * The path tokens. Logically, this fill is immutable. However, it's changed by the equals
     * methods if it detects equal fields.
     */
    private String[] segments;
    
    public XUri(String uri) {
        segments = Strings.split(uri, SEP);
    }
    
    public XUri(String[] toks) {
        this(toks, 0, toks.length);
    }
    
    public XUri(String[] segs, int start, int count) {
        if (start + count > segs.length) {
            throw new XAssertionFailed();
        }
        this.segments = new String[count];
        System.arraycopy(segs, start, segments, 0, count);
    }
    
    /**
     ** Check whether this is the root.
     **/
    public int size() {
        return segments.length;
    }
    
    public boolean isRoot() {
        return size() == 0;
    }
    
    public String segment(int i) {
        return segments[i];
    }
    
    /**
     * @return null if size() == 0
     */
    public String firstSegment() {
        return segments.length == 0? null : segments[0];
    }
    
    /**
     * @return null if size() == 0
     */
    public String lastSegment() {
        return segments.length == 0? null : segments[segments.length - 1];
    }
    
    /**
     * Similar to String.substring.
     */
    public XUri suburi(int start) {
        return suburi(start, segments.length - start);
    }
    
    /**
     * Similar to String.substring
     */
    public XUri suburi(int start, int count) {
        return new XUri(segments, start, count);
    }
    
    public XUri append(XUri op) {
        String[] segs;
        
        segs = new String[segments.length + op.segments.length];
        System.arraycopy(segments, 0, segs, 0, segments.length);
        System.arraycopy(op.segments, 0, segs, segments.length, op.segments.length);
        return new XUri(segs);  // TODO: expensive -- array cloned again
    }
    
    public XUri append(String segment) {
        String[] segs;
        
        segs = new String[segments.length + 1];
        System.arraycopy(segments, 0, segs, 0, segments.length);
        segs[segments.length] = segment;
        return new XUri(segs);
    }
    
    /**
     * Return the parent.
     * Example: for /a/b/c returns: /a/b
     *
     * @return null if this.size() == 0, none-null otherwise
     */
    public XUri getParent() {
        if (segments.length == 0) {
            return null;
        } else {
            return suburi(0, segments.length - 1 );
        }
    }
    
    /** caches toString result */
    private String uriStr = null;
    
    /**
     * Return string representation.
     */
    public String toString() {
        StringBuffer b;
        int i;
        
        if (uriStr == null) {
            if (segments.length == 0) {
                uriStr = SEP;
            } else {
                b = new StringBuffer();
                for (i = 0; i < segments.length; i++) {
                    b.append(SEP).append(segments[i]);
                }
                uriStr = b.toString();
            }
        }
        return uriStr;
    }
    
    public void addPrefixes(Collection col) {
        int i;
        
        for (i = 1; i < segments.length; i++) {
            col.add(suburi(0, i).toString());
        }
    }
    
    //-- comparison
    
    public static final int NE = 0;
    public static final int EQ = 1;
    public static final int PREFIX = 2;
    public static final int INV_PREFIX = 3;
    
    public int compare(XUri uri) {
        int i;
        int min;
        
        min = Math.min(segments.length, uri.segments.length);
        for (i = 0; i < min; i++) {
            if (!segments[i].equals(uri.segments[i])) {
                return NE;
            }
        }
        if (segments.length < uri.segments.length) {
            return PREFIX;
        } else if (segments.length > uri.segments.length) {
            return INV_PREFIX;
        } else {
            return EQ;
        }
    }
    
    /**
     ** Check whether this Uri corresponds to a top-level folder
     **
     ** @return     true if the uriRel corresponds to a folder
     **/
    public boolean isFolder() {
        return (size() == 1 && !Strings.endsWithIgnoreCase(firstSegment(), XML_SUFF));
    }
    
    /**
     ** Check whether the uriRel is corresponds to an XML file
     ** @return     true if the uriRel corresponds to an XML file
     **/
    public boolean isXmlFile() {
        return size() > 0 && Strings.endsWithIgnoreCase(lastSegment(), XML_SUFF);
    }
    
    /**
     *
     */
    public int hashCode() {
        return segments[segments.length - 1].hashCode();
    }
    /**
     *
     */
    public boolean equals( Object o ) {
        XUri uri;
        
        if( o instanceof XUri ) {
            uri = (XUri) o;
            if (segments == uri.segments) {
                return true;
            }
            if (segments.length != uri.segments.length) {
                return false;
            }
            if (compare((XUri) o) == EQ) {
                segments = uri.segments;
                return true;
            }
        }
        return false;
    }
}


