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.cli.completers;
021    
022    import org.crsh.cli.descriptor.ParameterDescriptor;
023    import org.crsh.cli.spi.Completer;
024    import org.crsh.cli.spi.Completion;
025    
026    import java.util.Collection;
027    
028    public abstract class AbstractPathCompleter<P> implements Completer {
029    
030      protected abstract String getCurrentPath() throws Exception;
031    
032      protected abstract P getPath(String path) throws Exception;
033    
034      protected abstract boolean exists(P path) throws Exception;
035    
036      protected abstract boolean isDirectory(P path) throws Exception;
037    
038      protected abstract boolean isFile(P path) throws Exception;
039    
040      protected abstract Collection<P> getChilren(P path) throws Exception;
041    
042      protected abstract String getName(P path) throws Exception;
043    
044      public final Completion complete(ParameterDescriptor parameter, String prefix) throws Exception {
045    
046        // Handle empty dir
047        if (!prefix.startsWith("/")) {
048          String currentPath = getCurrentPath();
049          if (!currentPath.endsWith("/")) {
050            currentPath += "/";
051          }
052          if (prefix.length() > 0) {
053            prefix = currentPath + prefix;
054          } else {
055            prefix = currentPath;
056          }
057        }
058    
059        //
060        P f = getPath(prefix);
061    
062        //
063        if (exists(f)) {
064          if (isDirectory(f)) {
065            if (prefix.endsWith("/")) {
066              Collection<P> children = getChilren(f);
067              if (children != null) {
068                if (children.size() > 0) {
069                  return listDir(f, "");
070                } else {
071                  return Completion.create();
072                }
073              } else {
074                return Completion.create();
075              }
076            } else {
077              Collection<P> children = getChilren(f);
078              if (children == null) {
079                return Completion.create();
080              } else {
081                return Completion.create("/", false);
082              }
083            }
084          } else if (isFile(f)) {
085            return Completion.create("", true);
086          }
087          return Completion.create();
088        } else {
089          int pos = prefix.lastIndexOf('/');
090          if (pos != -1) {
091            String filter;
092            if (pos == 0) {
093              f = getPath("/");
094              filter = prefix.substring(1);
095            } else {
096              f = getPath(prefix.substring(0, pos));
097              filter = prefix.substring(pos + 1);
098            }
099            if (exists(f)) {
100              if (isDirectory(f)) {
101                return listDir(f, filter);
102              } else {
103                return Completion.create();
104              }
105            } else {
106              return Completion.create();
107            }
108          } else {
109            return Completion.create();
110          }
111        }
112      }
113    
114      private Completion listDir(P dir, final String filter) throws Exception {
115        Collection<P> children = getChilren(dir);
116        if (children != null) {
117          Completion.Builder builder = Completion.builder(filter);
118          for (P child : children) {
119            String name = getName(child);
120            if (name.startsWith(filter)) {
121              String suffix = name.substring(filter.length());
122              if (isDirectory(child)) {
123                Collection<P> grandChildren = getChilren(child);
124                if (grandChildren != null) {
125                  builder.add(suffix + "/", false);
126                } else {
127                  // Skip it
128                }
129              } else {
130                builder.add(suffix, true);
131              }
132            }
133          }
134          return builder.build();
135        } else {
136          return Completion.create();
137        }
138      }
139    }