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