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
020package org.crsh.cli.completers;
021
022import org.crsh.cli.descriptor.ParameterDescriptor;
023import org.crsh.cli.spi.Completer;
024import org.crsh.cli.spi.Completion;
025
026import java.io.File;
027import java.util.Collection;
028
029public 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}