package com.bradmcevoy.common;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

/** Immutable
 */
public class Path implements Serializable {

    private static final long serialVersionUID = -8411900835514833454L;
    private final Path parent;
    private final String name;
    public static final Path root = new Path();
    private int hash;
    private final int length;
    public static final LengthComparator LENGTH_COMPARATOR = new LengthComparator();


    public static Path path( Path parent, String path ) {
        if( path == null )
            throw new NullPointerException( "The path parameter may not be null" );
        return split( parent, path );
    }

    public static Path path( String path ) {
        if( path == null || path.length() == 0 ) return root;
        return split( null, path );
    }

    private static Path split( Path startFrom, String s ) {
        Path parent = startFrom;
        StringBuffer sb = null;
        for( int i = 0; i < s.length(); i++ ) {
            char c = s.charAt( i );
            switch( c ) {
                case '/':
                    if( sb == null ) {
                        parent = root;
                    } else {
                        if( sb.length() > 0 ) {
                            String ss = sb.toString();
                            if( parent != null ) parent = parent.child( ss );
                            else parent = new Path( null, ss );
                        }
                        sb = null;
                    }
                    break;
//                case ' ':
//                    // ignore
//                    break;
                default:
                    if( sb == null ) sb = new StringBuffer();
                    sb.append( c );
            }
        }
        if( sb != null ) {
            if( sb.length() > 0 ) {
                String ss = sb.toString();
                if( parent != null ) parent = parent.child( ss );
                else parent = new Path( null, ss );
            }
        }

        return parent;
    }

    private Path() {
        this.parent = null;
        this.name = null;
        length = 0;
    }

    private Path( Path parent, String name ) {
        if( name == null )
            throw new IllegalArgumentException( "name may not be null" );
        this.parent = parent;
        this.name = name;
        if( this.parent != null ) {
            this.length = this.parent.length + 1;
        } else {
            this.length = 1;
        }
    }


    public int getLength() {
        return length;
    }

    public String[] getParts() {
        String[] arr = new String[length];
        Path p = this;
        int i = length;
        while( i > 0 ) {
            arr[--i] = p.getName();
            p = p.getParent();
        }
        return arr;
    }

    /**
     * 
     * @return - the first part of the path. ie a/b/c returns a
     */
    public String getFirst() {
        Path p = this;
        while( p.getParent() != null ) {
            Path next = p.getParent();
            if( next.getName() == null ) return p.getName();
            p = next;
        }
        if( p != null ) return p.getName();
        return null;
    }

    public List<String> getAfterFirst() {
        List<String> afterFirst = new ArrayList<String>();
        Path p = this;
        while( !p.getParent().isRoot() ) {
            afterFirst.add( 0, p.getName() );
            p = p.getParent();
        }
        return afterFirst;
    }

    public Path getStripFirst() {
        return stripFirst( this );
    }

    Path stripFirst( Path p ) {
        Path pParent = p.getParent();
        if( pParent.isRoot() ) return root;
        pParent = stripFirst( pParent );
        return new Path( pParent, p.getName() );
    }

    public String getName() {
        return name;
    }

    public Path getParent() {
        return parent;
    }

    public boolean isRoot() {
        return ( ( parent == null ) && ( name == null ) );
    }

    public String toPath() {
        if( isRoot() ) return "";
        if( parent == null ) return name;
        return parent.toString() + '/' + name;
    }

    @Override
    public String toString() {
        return toPath();
    }

    public String toString( String delimiter ) {
        if( parent == null ) return "";
        if( parent == null ) return name;
        return parent.toString( delimiter ) + delimiter + name;
    }

    public static Path root() {
        return root;
    }

    @Override
    public int hashCode() {
        if( hash == 0 ) {
            if( parent == null ) {
                hash = 158;
            } else {
                hash = parent.hashCode() ^ name.hashCode();
            }
        }
        return hash;
    }

    @Override
    public boolean equals( Object obj ) {
        if( obj == null ) return false;
        if( obj instanceof Path ) {
            Path p2 = (Path) obj;
            if( this.isRoot() ) {
                return p2.isRoot();
            } else {
                if( parentEquals( this, p2 ) ) {
                    return this.name.equals( p2.name );
                } else {
                    return false;
                }
            }
        } else {
            return false;
        }
    }

    private static boolean parentEquals( Path p1, Path p2 ) {
        if( p2.parent == null ) {
            return p1.parent == null;
        } else {
            return p2.parent.equals( p1.parent );
        }
    }

    public Path child( String name ) {
        System.out.println( "this name: " + this.name );
        System.out.println( "this root: " + this.isRoot() );
        Path ch = new Path( this, name );
        System.out.println( "parent name: " + ch.getParent().name );
        return ch;
    }

    public boolean isRelative() {
        if( parent == null ) {
            return !isRoot();
        } else {
            return parent.isRelative();
        }
    }

    public static class LengthComparator implements Comparator<Path> {

        public int compare( Path o1, Path o2 ) {
            Integer i1 = o1.getLength();
            Integer i2 = o2.getLength();
            return i1.compareTo( i2 );
        }
    }
}

@@ -5819,224 +5819,34 @@
     
-System.out.println( %22this name: %22 + this.name );%0D%0A        System.out.println( %22this root: %22 + this.isRoot() );%0D%0A        Path ch = new Path( this, name );%0D%0A        System.out.println( %22parent name: %22 + ch.getParent().
+Path ch = new Path( this, 
 name

remove souts