001    /*
002     * Copyright (C) 2012 eXo Platform SAS.
003     *
004     * This is free software; you can redistribute it and/or modify it
005     * under the terms of the GNU Lesser General Public License as
006     * published by the Free Software Foundation; either version 2.1 of
007     * the License, or (at your option) any later version.
008     *
009     * This software is distributed in the hope that it will be useful,
010     * but WITHOUT ANY WARRANTY; without even the implied warranty of
011     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012     * Lesser General Public License for more details.
013     *
014     * You should have received a copy of the GNU Lesser General Public
015     * License along with this software; if not, write to the Free
016     * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
017     * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
018     */
019    
020    package org.crsh.vfs;
021    
022    import java.util.Iterator;
023    import java.util.NoSuchElementException;
024    
025    public final class Path implements Iterable<String> {
026    
027      /** . */
028      private final boolean dir;
029    
030      /** . */
031      private final String[] names;
032    
033      /** . */
034      private String value;
035    
036      public static Path get(Path parent, String name, boolean dir) {
037        if (!parent.dir) {
038          throw new IllegalArgumentException("Not a dir");
039        }
040        int length = parent.names.length;
041        String[] names = new String[length + 1];
042        System.arraycopy(parent.names, 0, names, 0, length);
043        names[length] = name;
044        return new Path(dir, names);
045      }
046    
047      public static Path get(String s) {
048        if (s.length() == 0) {
049          throw new IllegalArgumentException("No empty path");
050        }
051        if (s.charAt(0) != '/') {
052          throw new IllegalArgumentException("Path must begin with a '/'");
053        }
054    
055        // Count
056        int end = s.length();
057    
058        //
059        int count = 0;
060        int prev = 1;
061        while (true) {
062          int next = s.indexOf('/', prev);
063          if (next == -1) {
064            if (prev < end) {
065              count++;
066            }
067            break;
068          } else if (next - prev > 0) {
069            count++;
070          }
071          prev = next + 1;
072        }
073    
074        //
075        String[] names = new String[count];
076        prev = 1;
077        count = 0;
078        boolean dir;
079        while (true) {
080          int next = s.indexOf('/', prev);
081          if (next == -1) {
082            if (prev < end) {
083              names[count] = s.substring(prev);
084              dir = false;
085            } else {
086              dir = true;
087            }
088            break;
089          } else if (next - prev > 0) {
090            names[count++] = s.substring(prev, next);
091          }
092          prev = next + 1;
093        }
094    
095        //
096        return new Path(dir, names);
097      }
098    
099      private Path(boolean dir, String[] names) {
100        this.dir = dir;
101        this.names = names;
102      }
103    
104      public Iterator<String> iterator() {
105        return new Iterator<String>() {
106          int index = 0;
107          public boolean hasNext() {
108            return index < names.length;
109          }
110          public String next() {
111            if (index < names.length) {
112              return names[index++];
113            } else {
114              throw new NoSuchElementException();
115            }
116          }
117          public void remove() {
118            throw new UnsupportedOperationException();
119          }
120        };
121      }
122    
123      public int getSize() {
124        return names.length;
125      }
126    
127      public boolean isDir() {
128        return dir;
129      }
130    
131      public String getName() {
132        return names.length > 0 ? names[names.length - 1] : "";
133      }
134    
135      public boolean isChildOf(Path parent) {
136        if (parent.dir) {
137          int length = parent.names.length;
138          if (names.length == length + 1) {
139            for (int i = 0;i < length;i++) {
140              if (names[i].equals(parent.names[i])) {
141                return false;
142              }
143            }
144            return true;
145          }
146        }
147        return false;
148      }
149    
150      @Override
151      public boolean equals(Object o) {
152        if (o == this) {
153          return true;
154        }
155        if (o instanceof Path) {
156          Path that = (Path)o;
157          int length = that.names.length;
158          if (names.length == length) {
159            for (int i = 0;i < length;i++) {
160              if (!names[i].equals(that.names[i])) {
161                return false;
162              }
163            }
164            return true;
165          }
166        }
167        return false;
168      }
169    
170      @Override
171      public int hashCode() {
172        int hashCode = dir ? 1 : 0;
173        for (int i = names.length - 1;i >= 0;i--) {
174          hashCode = hashCode * 41 + names[i].hashCode();
175        }
176        return hashCode;
177      }
178    
179      public String getValue() {
180        if (value == null) {
181          StringBuilder sb = new StringBuilder(8 * names.length);
182          for (String name : names) {
183            sb.append('/').append(name);
184          }
185          if (dir) {
186            sb.append('/');
187          }
188          value = sb.toString();
189        }
190        return value;
191      }
192    
193      public String toString() {
194        return "Path[value=" + getValue() + "]";
195      }
196    }