content: /*
   * This library is part of OpenCms -
   * the Open Source Content Management System
   *
   * Copyright (c) Alkacon Software GmbH & Co. KG (https://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 & Co. KG, please see the
   * company website: https://www.alkacon.com
   *
   * For further information about OpenCms, please see the
   * project website: https://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.workplace.commons;
  
  import org.opencms.file.CmsObject;
  import org.opencms.file.CmsProperty;
  import org.opencms.file.CmsPropertyDefinition;
  import org.opencms.file.CmsResource;
  import org.opencms.file.CmsResourceFilter;
  import org.opencms.i18n.CmsEncoder;
  import org.opencms.i18n.CmsMessages;
  import org.opencms.jsp.CmsJspActionElement;
  import org.opencms.jsp.CmsJspNavBuilder;
  import org.opencms.jsp.CmsJspNavBuilder.Visibility;
  import org.opencms.jsp.CmsJspNavElement;
  import org.opencms.main.CmsException;
  import org.opencms.main.CmsLog;
  import org.opencms.main.OpenCms;
  import org.opencms.security.CmsPermissionSet;
  import org.opencms.util.CmsStringUtil;
  import org.opencms.workplace.CmsDialog;
  import org.opencms.workplace.CmsWorkplace;
  import org.opencms.workplace.CmsWorkplaceSettings;
  
  import java.util.ArrayList;
  import java.util.List;
  
  import javax.servlet.http.HttpServletRequest;
  import javax.servlet.http.HttpServletResponse;
  import javax.servlet.jsp.JspException;
  import javax.servlet.jsp.PageContext;
  
  import org.apache.commons.logging.Log;
  
  /**
   * Provides methods for the change navigation dialog.<p>
   *
   * The following files use this class:
   * <ul>
   * <li>/commons/chnav.jsp
   * </ul>
   * <p>
   *
   * @since 6.0.0
   */
  public class CmsChnav extends CmsDialog {
  
      /** Value for the action: change the navigation. */
      public static final int ACTION_CHNAV = 100;
  
      /** The dialog type. */
      public static final String DIALOG_TYPE = "chnav";
  
      /** Request parameter name for the navigation position. */
      public static final String PARAM_NAVPOS = "navpos";
  
      /** Request parameter name for the navigation text. */
      public static final String PARAM_NAVTEXT = "navtext";
  
      /** The log object for this class. */
      private static final Log LOG = CmsLog.getLog(CmsChnav.class);
  
      /** The NavPos parameter. */
      private String m_paramNavpos;
  
      /** The NavText parameter. */
      private String m_paramNavtext;
  
      /**
       * Public constructor.<p>
       *
       * @param jsp an initialized JSP action element
       */
      public CmsChnav(CmsJspActionElement jsp) {
  
          super(jsp);
      }
  
      /**
       * Public constructor with JSP variables.<p>
       *
       * @param context the JSP page context
       * @param req the JSP request
       * @param res the JSP response
       */
      public CmsChnav(PageContext context, HttpServletRequest req, HttpServletResponse res) {
  
          this(new CmsJspActionElement(context, req, res));
      }
  
      /**
       * Builds the HTML for the select box of the navigation position.<p>
       *
       * @param cms the CmsObject
       * @param filename the current file
       * @param attributes optional attributes for the &lt;select&gt; tag, do not add the "name" atribute!
       * @param messages the localized workplace messages
       *
       * @return the HTML for a navigation position select box
       */
      public static String buildNavPosSelector(CmsObject cms, String filename, String attributes, CmsMessages messages) {
  
          // get current file navigation element
          CmsJspNavBuilder navBuilder = new CmsJspNavBuilder(cms);
          CmsJspNavElement curNav = navBuilder.getNavigationForResource(filename);
  
          // get the parent folder of the current file
          filename = CmsResource.getParentFolder(filename);
  
          // get navigation of the current folder
          List<CmsJspNavElement> navList = navBuilder.getNavigationForFolder(
              filename,
              Visibility.includeHidden,
              CmsResourceFilter.DEFAULT);
          float maxValue = 0;
          float nextPos = 0;
  
          // calculate value for the first navigation position
          float firstValue = 1;
          if (navList.size() > 0) {
              try {
                  CmsJspNavElement ne = navList.get(0);
                  maxValue = ne.getNavPosition();
              } catch (Exception e) {
                  // should usually never happen
                  LOG.error(e.getLocalizedMessage());
              }
          }
  
          if (maxValue != 0) {
              firstValue = maxValue / 2;
          }
  
          List<String> options = new ArrayList<String>(navList.size() + 1);
          List<String> values = new ArrayList<String>(navList.size() + 1);
  
          // add the first entry: before first element
          options.add(messages.key(Messages.GUI_CHNAV_POS_FIRST_0));
          values.add(firstValue + "");
  
          // show all present navigation elements in box
          for (int i = 0; i < navList.size(); i++) {
              CmsJspNavElement ne = navList.get(i);
              String navText = ne.getNavText();
              float navPos = ne.getNavPosition();
              // get position of next nav element
              nextPos = navPos + 2;
              if ((i + 1) < navList.size()) {
                  nextPos = navList.get(i + 1).getNavPosition();
              }
              // calculate new position of current nav element
              float newPos;
              if ((nextPos - navPos) > 1) {
                  newPos = navPos + 1;
              } else {
                  newPos = (navPos + nextPos) / 2;
              }
  
              // check new maxValue of positions and increase it
              if (navPos > maxValue) {
                  maxValue = navPos;
              }
  
              // if the element is the current file, mark it in selectbox
              if ((curNav != null) && curNav.getNavText().equals(navText) && (curNav.getNavPosition() == navPos)) {
                  options.add(
                      CmsEncoder.escapeHtml(
                          messages.key(Messages.GUI_CHNAV_POS_CURRENT_1, new Object[] {ne.getFileName()})));
                  values.add("-1");
              } else {
                  options.add(CmsEncoder.escapeHtml(navText + " [" + ne.getFileName() + "]"));
                  values.add(newPos + "");
              }
          }
  
          // add the entry: at the last position
          options.add(messages.key(Messages.GUI_CHNAV_POS_LAST_0));
          values.add((maxValue + 1) + "");
  
          // add the entry: no change
          options.add(messages.key(Messages.GUI_CHNAV_NO_CHANGE_0));
          if ((curNav != null) && (curNav.getNavPosition() == Float.MAX_VALUE)) {
              // current resource has no valid position, use "last position"
              values.add((maxValue + 1) + "");
          } else {
              // current resource has valid position, use "-1" for no change
              values.add("-1");
          }
  
          if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(attributes)) {
              attributes = " " + attributes;
          } else {
              attributes = "";
          }
          return CmsWorkplace.buildSelect(
              "name=\"" + PARAM_NAVPOS + "\"" + attributes,
              options,
              values,
              values.size() - 1,
              true);
      }
  
      /**
       * Performs the navigation change.<p>
       *
       * @throws JspException if including a JSP subelement is not successful
       */
      public void actionChangeNav() throws JspException {
  
          // save initialized instance of this class in request attribute for included sub-elements
          getJsp().getRequest().setAttribute(SESSION_WORKPLACE_CLASS, this);
  
          // get request parameters
          String filename = getParamResource();
          // do not use #getParamNavText since it is decoded, see CmsWorkplace#fillParamValues(HttpServletRequest)
          String newText = getJsp().getRequest().getParameter(PARAM_NAVTEXT);
          String selectedPosString = getParamNavpos();
  
          try {
              // lock resource if autolock is enabled
              checkLock(getParamResource());
              // save the new NavText if not null
              if (newText != null) {
                  CmsProperty newNavText = new CmsProperty();
                  newNavText.setName(CmsPropertyDefinition.PROPERTY_NAVTEXT);
                  CmsProperty oldNavText = getCms().readPropertyObject(
                      filename,
                      CmsPropertyDefinition.PROPERTY_NAVTEXT,
                      false);
                  if (oldNavText.isNullProperty()) {
                      // property value was not already set
                      if (OpenCms.getWorkplaceManager().isDefaultPropertiesOnStructure()) {
                          newNavText.setStructureValue(newText);
                      } else {
                          newNavText.setResourceValue(newText);
                      }
                  } else {
                      if (oldNavText.getStructureValue() != null) {
                          newNavText.setStructureValue(newText);
                          newNavText.setResourceValue(oldNavText.getResourceValue());
                      } else {
                          newNavText.setResourceValue(newText);
                      }
                  }
  
                  String oldStructureValue = oldNavText.getStructureValue();
                  String newStructureValue = newNavText.getStructureValue();
                  if (CmsStringUtil.isEmpty(oldStructureValue)) {
                      oldStructureValue = CmsProperty.DELETE_VALUE;
                  }
                  if (CmsStringUtil.isEmpty(newStructureValue)) {
                      newStructureValue = CmsProperty.DELETE_VALUE;
                  }
  
                  String oldResourceValue = oldNavText.getResourceValue();
                  String newResourceValue = newNavText.getResourceValue();
                  if (CmsStringUtil.isEmpty(oldResourceValue)) {
                      oldResourceValue = CmsProperty.DELETE_VALUE;
                  }
                  if (CmsStringUtil.isEmpty(newResourceValue)) {
                      newResourceValue = CmsProperty.DELETE_VALUE;
                  }
  
                  // change nav text only if it has been changed
                  if (!oldResourceValue.equals(newResourceValue) || !oldStructureValue.equals(newStructureValue)) {
                      getCms().writePropertyObject(getParamResource(), newNavText);
                  }
              }
  
              // determine the selected position
              float selectedPos = -1;
              try {
                  selectedPos = Float.parseFloat(selectedPosString);
              } catch (Exception e) {
                  // can usually be ignored
                  if (LOG.isInfoEnabled()) {
                      LOG.info(e.getLocalizedMessage());
                  }
              }
  
              // only update the position if a change is requested
              if (selectedPos != -1) {
                  CmsProperty newNavPos = new CmsProperty();
                  newNavPos.setName(CmsPropertyDefinition.PROPERTY_NAVPOS);
                  CmsProperty oldNavPos = getCms().readPropertyObject(
                      filename,
                      CmsPropertyDefinition.PROPERTY_NAVPOS,
                      false);
                  if (oldNavPos.isNullProperty()) {
                      // property value was not already set
                      if (OpenCms.getWorkplaceManager().isDefaultPropertiesOnStructure()) {
                          newNavPos.setStructureValue(selectedPosString);
                      } else {
                          newNavPos.setResourceValue(selectedPosString);
                      }
                  } else {
                      if (oldNavPos.getStructureValue() != null) {
                          newNavPos.setStructureValue(selectedPosString);
                          newNavPos.setResourceValue(oldNavPos.getResourceValue());
                      } else {
                          newNavPos.setResourceValue(selectedPosString);
                      }
                  }
                  getCms().writePropertyObject(filename, newNavPos);
              }
          } catch (Throwable e) {
              // error during chnav, show error dialog
              includeErrorpage(this, e);
          }
          // chnav operation was successful, return to workplace
          actionCloseDialog();
      }
  
      /**
       * Builds the HTML for the select box of the navigation position.<p>
       *
       * @return the HTML for a navigation position select box
       */
      public String buildNavPosSelector() {
  
          return buildNavPosSelector(getCms(), getParamResource(), null, getMessages());
      }
  
      /**
       * Returns the escaped NavText property value of the current resource.<p>
       *
       * @return the NavText property value of the current resource
       */
      public String getCurrentNavText() {
  
          try {
              String navText = getCms().readPropertyObject(
                  getParamResource(),
                  CmsPropertyDefinition.PROPERTY_NAVTEXT,
                  false).getValue();
              if (navText == null) {
                  navText = "";
              }
              return CmsEncoder.escapeXml(navText);
          } catch (CmsException e) {
              // can usually be ignored
              if (LOG.isInfoEnabled()) {
                  LOG.info(e.getLocalizedMessage());
              }
              return "";
          }
  
      }
  
      /**
       * Returns the value of the navigation position parameter,
       * or null if this parameter was not provided.<p>
       *
       * The navigation position parameter defines the new value for
       * the NavPos property.<p>
       *
       * @return the value of the target parameter
       */
      public String getParamNavpos() {
  
          return m_paramNavpos;
      }
  
      /**
       * Returns the value of the navigation text parameter,
       * or null if this parameter was not provided.<p>
       *
       * The navigation text parameter defines the new value for
       * the NavText property.<p>
       *
       * @return the value of the target parameter
       */
      public String getParamNavtext() {
  
          return m_paramNavtext;
      }
  
      /**
       * Sets the value of the navigation position parameter.<p>
       *
       * @param value the value to set
       */
      public void setParamNavpos(String value) {
  
          m_paramNavpos = value;
      }
  
      /**
       * Sets the value of the navigation text parameter.<p>
       *
       * @param value the value to set
       */
      public void setParamNavtext(String value) {
  
          m_paramNavtext = value;
      }
  
      /**
       * @see org.opencms.workplace.CmsWorkplace#initWorkplaceRequestValues(org.opencms.workplace.CmsWorkplaceSettings, javax.servlet.http.HttpServletRequest)
       */
      @Override
      protected void initWorkplaceRequestValues(CmsWorkplaceSettings settings, HttpServletRequest request) {
  
          // fill the parameter values in the get/set methods
          fillParamValues(request);
  
          // check the required permissions to change navigation of the resource
          if (!checkResourcePermissions(CmsPermissionSet.ACCESS_WRITE, false)) {
              // no write permissions for the resource, set cancel action to close dialog
              setParamAction(DIALOG_CANCEL);
          }
  
          // set the dialog type
          setParamDialogtype(DIALOG_TYPE);
          // set the action for the JSP switch
          if (DIALOG_TYPE.equals(getParamAction())) {
              setAction(ACTION_CHNAV);
          } else if (DIALOG_LOCKS_CONFIRMED.equals(getParamAction())) {
              setAction(ACTION_LOCKS_CONFIRMED);
          } else if (DIALOG_CANCEL.equals(getParamAction())) {
              setAction(ACTION_CANCEL);
          } else {
              setAction(ACTION_DEFAULT);
              // build title for chnav dialog
              setParamTitle(key(Messages.GUI_CHNAV_1, new Object[] {CmsResource.getName(getParamResource())}));
          }
      }
  
  }
  