gt:         folder = CmsResource.getFolderPath(folder);
context: /*
   * This library is part of OpenCms -
   * the Open Source Content Management System
   *
   * Copyright (c) Alkacon Software GmbH (http://www.alkacon.com)
   *
   * This library is free software; you can redistribute it and/or
   * modify it under the terms of the GNU Lesser General Public
   * License as published by the Free Software Foundation; either
   * version 2.1 of the License, or (at your option) any later version.
   *
   * This library is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
   * Lesser General Public License for more details.
   *
   * For further information about Alkacon Software GmbH, please see the
   * company website: http://www.alkacon.com
   *
   * For further information about OpenCms, please see the
   * project website: http://www.opencms.org
   * 
   * You should have received a copy of the GNU Lesser General Public
   * License along with this library; if not, write to the Free Software
   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   */
  
  package org.opencms.jsp;
  
  import org.opencms.file.CmsObject;
  import org.opencms.file.CmsProperty;
  import org.opencms.file.CmsResource;
  import org.opencms.file.CmsResourceFilter;
  import org.opencms.main.CmsException;
  import org.opencms.main.CmsLog;
  
  import java.util.ArrayList;
  import java.util.Collections;
  import java.util.List;
  import java.util.Map;
  
  import org.apache.commons.logging.Log;
  
  /**
   * Bean to provide a convenient way to build navigation structures based on the
   * <code>{@link org.opencms.jsp.CmsJspNavElement}</code>.<p>
   *
   * Use this together with the <code>{@link org.opencms.jsp.CmsJspActionElement}</code>
   * to obtain navigation information based on the current users permissions.
   * For example, use <code>{@link #getNavigationForFolder(String)}</code> and pass the 
   * value of the current OpenCms user context uri obtained 
   * from <code>{@link org.opencms.file.CmsRequestContext#getUri()}</code> as argument to obtain a list
   * of all items in the navigation of the current folder. Then use a simple scriptlet to 
   * iterate over these items and create a HTML navigation.<p>
   * 
   * @since 6.0.0 
   * 
   * @see org.opencms.jsp.CmsJspNavElement
   */
  public class CmsJspNavBuilder {
  
      /** The log object for this class. */
      private static final Log LOG = CmsLog.getLog(CmsJspNavBuilder.class);
  
      /** The current CMS context. */
      protected CmsObject m_cms;
  
      /** The current request URI. */
      protected String m_requestUri;
  
      /** The current request folder. */
      protected String m_requestUriFolder;
  
      /**
       * Empty constructor, so that this bean can be initialized from a JSP.<p> 
       */
      public CmsJspNavBuilder() {
  
          // empty
      }
  
      /**
       * Default constructor.<p>
       * 
       * @param cms context provider for the current request
       */
      public CmsJspNavBuilder(CmsObject cms) {
  
          init(cms);
      }
  
      /**
       * Returns the full name (including VFS path) of the default file for this navigation element 
       * or <code>null</code> if the navigation element is not a folder.<p>
       * 
       * The default file of a folder is determined by the value of the property 
       * <code>default-file</code> or the system wide property setting.<p>
       * 
       * @param cms the CMS object
       * @param folder full name of the folder
       * 
       * @return the name of the default file
       * 
       * @deprecated use {@link CmsObject#readDefaultFile(String)} instead
       */
      @Deprecated
      public static String getDefaultFile(CmsObject cms, String folder) {
  
          if (folder.endsWith("/")) {
              try {
                  CmsResource defaultFile = cms.readDefaultFile(folder);
                  if (defaultFile != null) {
                      return cms.getSitePath(defaultFile);
                  }
              } catch (CmsException e) {
                  LOG.debug(e.getLocalizedMessage(), e);
              }
              return folder;
          }
          return null;
      }
  
      /**
       * Collect all navigation elements from the files in the given folder,
       * navigation elements are of class {@link CmsJspNavElement}.<p>
       *
       * @param cms context provider for the current request
       * @param folder the selected folder
       * 
       * @return a sorted (ascending to navigation position) list of navigation elements
       * 
       * @deprecated use {@link #getNavigationForFolder(String)} instead
       */
      @Deprecated
      public static List<CmsJspNavElement> getNavigationForFolder(CmsObject cms, String folder) {
  
          return new CmsJspNavBuilder(cms).getNavigationForFolder(folder);
      }
  
      /** 
       * Build a navigation for the folder that is either minus levels up 
       * from the given folder, or that is plus levels down from the 
       * root folder towards the given folder.<p> 
       * 
       * If level is set to zero the root folder is used by convention.<p>
       * 
       * @param cms context provider for the current request
       * @param folder the selected folder
       * @param level if negative, walk this many levels up, if positive, walk this many 
       *              levels down from root folder 
       *              
       * @return a sorted (ascending to navigation position) list of navigation elements
       * 
       * @deprecated use {@link #getNavigationForFolder(String, int)} instead
       */
      @Deprecated
      public static List<CmsJspNavElement> getNavigationForFolder(CmsObject cms, String folder, int level) {
  
          return new CmsJspNavBuilder(cms).getNavigationForFolder(folder, level);
      }
  
      /**
       * Returns a navigation element for the named resource.<p>
       * 
       * @param cms context provider for the current request
       * @param resource the resource name to get the navigation information for, 
       *              must be a full path name, e.g. "/docs/index.html"
       *              
       * @return a navigation element for the given resource
       * 
       * @deprecated use {@link #getNavigationForResource(String)} instead
       */
      @Deprecated
      public static CmsJspNavElement getNavigationForResource(CmsObject cms, String resource) {
  
          return new CmsJspNavBuilder(cms).getNavigationForResource(resource);
      }
  
      /**
       * Builds a tree navigation for the folders between the provided start and end level.<p>
       * 
       * A tree navigation includes all navigation elements that are required to display a tree structure.
       * However, the data structure is a simple list.
       * Each of the navigation elements in the list has the {@link CmsJspNavElement#getNavTreeLevel()} set
       * to the level it belongs to. Use this information to distinguish between the navigation levels.<p>
       * 
       * @param cms context provider for the current request
       * @param folder the selected folder
       * @param startlevel the start level
       * @param endlevel the end level
       * 
       * @return a sorted list of navigation elements with the navigation tree level property set 
       * 
       * @deprecated use {@link #getNavigationForResource(String)} instead
       */
      @Deprecated
      public static List<CmsJspNavElement> getNavigationTreeForFolder(
          CmsObject cms,
          String folder,
          int startlevel,
          int endlevel) {
  
          return new CmsJspNavBuilder(cms).getNavigationTreeForFolder(folder, startlevel, endlevel);
      }
  
      /**
       * This method builds a complete navigation tree with entries of all branches 
       * from the specified folder.<p>
       * 
       * For an unlimited depth of the navigation (i.e. no <code>endLevel</code>), 
       * set the <code>endLevel</code> to a value &lt; 0.<p>
       * 
       * 
       * @param cms the current CMS context
       * @param folder the root folder of the navigation tree
       * @param endLevel the end level of the navigation
       * 
       * @return list of navigation elements, in depth first order
       * 
       * @deprecated use {@link #getNavigationForResource(String)} instead
       */
      @Deprecated
      public static List<CmsJspNavElement> getSiteNavigation(CmsObject cms, String folder, int endLevel) {
  
          return new CmsJspNavBuilder(cms).getSiteNavigation(folder, endLevel);
      }
  
      /**
       * Build a "bread crumb" path navigation to the current folder.<p>
       * 
       * @return ArrayList sorted list of navigation elements
       * 
       * @see #getNavigationBreadCrumb(String, int, int, boolean) 
       */
      public List<CmsJspNavElement> getNavigationBreadCrumb() {
  
          return getNavigationBreadCrumb(m_requestUriFolder, 0, -1, true);
      }
  
      /**
       * Build a "bread crumb" path navigation to the current folder.<p>
       * 
       * @param startlevel the start level, if negative, go down |n| steps from selected folder
       * @param currentFolder include the selected folder in navigation or not
       * 
       * @return sorted list of navigation elements
       * 
       * @see #getNavigationBreadCrumb(String, int, int, boolean) 
       */
      public List<CmsJspNavElement> getNavigationBreadCrumb(int startlevel, boolean currentFolder) {
  
          return getNavigationBreadCrumb(m_requestUriFolder, startlevel, -1, currentFolder);
      }
  
      /**
       * Build a "bread crumb" path navigation to the current folder.<p>
       * 
       * @param startlevel the start level, if negative, go down |n| steps from selected folder
       * @param endlevel the end level, if -1, build navigation to selected folder
       * 
       * @return sorted list of navigation elements
       * 
       * @see #getNavigationBreadCrumb(String, int, int, boolean) 
       */
      public List<CmsJspNavElement> getNavigationBreadCrumb(int startlevel, int endlevel) {
  
          return getNavigationBreadCrumb(m_requestUriFolder, startlevel, endlevel, true);
      }
  
      /** 
       * Build a "bread crumb" path navigation to the given folder.<p>
       * 
       * The <code>startlevel</code> marks the point where the navigation starts from, if negative, 
       * the count of steps to go down from the given folder.<p>
       *  
       * The <code>endlevel</code> is the maximum level of the navigation path, set it to -1 to build the
       * complete navigation to the given folder.<p>
       * 
       * You can include the given folder in the navigation by setting <code>currentFolder</code> to 
       * <code>true</code>, otherwise <code>false</code>.<p> 
       * 
       * @param folder the selected folder
       * @param startlevel the start level, if negative, go down |n| steps from selected folder
       * @param endlevel the end level, if -1, build navigation to selected folder
       * @param currentFolder include the selected folder in navigation or not
       * 
       * @return sorted list of navigation elements
       */
      public List<CmsJspNavElement> getNavigationBreadCrumb(
          String folder,
          int startlevel,
          int endlevel,
          boolean currentFolder) {
  
          List<CmsJspNavElement> result = new ArrayList<CmsJspNavElement>();
  
          int level = CmsResource.getPathLevel(folder);
          // decrease folder level if current folder is not displayed
          if (!currentFolder) {
              level -= 1;
          }
          // check current level and change endlevel if it is higher or -1
          if ((level < endlevel) || (endlevel == -1)) {
              endlevel = level;
          }
  
          // if startlevel is negative, display only |startlevel| links
          if (startlevel < 0) {
              startlevel = endlevel + startlevel + 1;
              if (startlevel < 0) {
                  startlevel = 0;
              }
          }
  
          // create the list of navigation elements     
          for (int i = startlevel; i <= endlevel; i++) {
              String navFolder = CmsResource.getPathPart(folder, i);
              CmsJspNavElement e = getNavigationForResource(navFolder);
              // add element to list
              result.add(e);
          }
  
          return result;
      }
  
      /**
       * Collect all navigation elements from the files of the folder of the current request URI.<p>
       *
       * @return a sorted (ascending to navigation position) list of navigation elements
       */
      public List<CmsJspNavElement> getNavigationForFolder() {
  
          return getNavigationForFolder(m_requestUriFolder);
      }
  
      /** 
       * Build a navigation for the folder that is either minus levels up 
       * from of the folder of the current request URI, or that is plus levels down from the 
       * root folder towards the current request URI.<p> 
       * 
       * If level is set to zero the root folder is used by convention.<p>
       * 
       * @param level if negative, walk this many levels up, if positive, walk this many 
       *                  levels down from root folder 
       * @return a sorted (ascending to navigation position) list of navigation elements
       */
      public List<CmsJspNavElement> getNavigationForFolder(int level) {
  
          return getNavigationForFolder(m_requestUriFolder, level);
      }
  
      /**
       * Collect all navigation visible elements from the files in the given folder.<p>
       *
       * @param folder the selected folder
       * 
       * @return A sorted (ascending to navigation position) list of navigation elements
       */
      public List<CmsJspNavElement> getNavigationForFolder(String folder) {
  
          return getNavigationForFolder(folder, false, CmsResourceFilter.DEFAULT);
      }
  
      /**
       * Collect all navigation elements from the files in the given folder.<p>
       *
       * @param folder the selected folder
       * @param includeInvisible <code>true</code> to include elements not visible in navigation
       * @param resourceFilter the filter to use reading the resources
       * 
       * @return A sorted (ascending to navigation position) list of navigation elements
       */
      public List<CmsJspNavElement> getNavigationForFolder(
          String folder,
          boolean includeInvisible,
          CmsResourceFilter resourceFilter) {
  
          folder = CmsResource.getFolderPath(folder);
          List<CmsJspNavElement> result = new ArrayList<CmsJspNavElement>();
  
          List<CmsResource> resources;
          try {
  
              resources = m_cms.getResourcesInFolder(folder, resourceFilter);
          } catch (Exception e) {
              // should never happen
              LOG.error(e.getLocalizedMessage(), e);
              return Collections.<CmsJspNavElement> emptyList();
          }
  
          for (CmsResource r : resources) {
              CmsJspNavElement element = getNavigationForResource(m_cms.getSitePath(r), resourceFilter);
              if ((element != null) && (includeInvisible || element.isInNavigation())) {
                  result.add(element);
              }
          }
          Collections.sort(result);
          return result;
      }
  
      /** 
       * Build a navigation for the folder that is either minus levels up 
       * from the given folder, or that is plus levels down from the 
       * root folder towards the given folder.<p> 
       * 
       * If level is set to zero the root folder is used by convention.<p>
       * 
       * @param folder the selected folder
       * @param level if negative, walk this many levels up, if positive, walk this many 
       *                  levels down from root folder 
       *                  
       * @return a sorted (ascending to navigation position) list of navigation elements
       */
      public List<CmsJspNavElement> getNavigationForFolder(String folder, int level) {
  
  