/**
   * Reads the resources available for processing based on the path parameters.
   *
   * <p>
   *
   * @return the resources available for processing based on the path parameters.
   */
  @SuppressWarnings("unchecked")
  private List<CmsResource> getResources() {

    List<CmsResource> result = new LinkedList<CmsResource>();
    CmsObject cms = this.getCms();
    CmsResourceFilter filter = CmsResourceFilter.ALL;
    try {
      for (String path : this.m_paths) {
        List<CmsResource> resources = cms.readResources(path, filter, true);
        // filter out any resource that is no XML content:
        for (CmsResource resource : resources) {
          if (resource.isFile()) {
            if (CmsResourceTypeXmlContent.isXmlContent(resource)) {
              result.add(resource);
            } else if (CmsResourceTypeXmlPage.isXmlPage(resource)) {
              result.add(resource);
            }
          }
        }
      }
    } catch (CmsException e) {
      LOG.error(Messages.get().getBundle().key(Messages.LOG_ERR_LANGUAGECOPY_READRESOURCES_0), e);
      result = Collections.emptyList();
    }

    return result;
  }
  /**
   * Performs the comment images operation.
   *
   * <p>
   *
   * @return true, if the resources were successfully processed, otherwise false
   * @throws CmsException if commenting is not successful
   */
  protected boolean performDialogOperation() throws CmsException {

    // lock the image gallery folder
    checkLock(getParamResource());

    Iterator i = getImages().iterator();
    // loop over all image resources to change the properties
    while (i.hasNext()) {
      CmsResource res = (CmsResource) i.next();
      String imageName = res.getName();
      String propertySuffix = "" + imageName.hashCode();

      // update the title property
      CmsProperty titleProperty =
          getCms().readPropertyObject(res, CmsPropertyDefinition.PROPERTY_TITLE, false);
      String newValue = getJsp().getRequest().getParameter(PREFIX_TITLE + propertySuffix);
      writeProperty(res, CmsPropertyDefinition.PROPERTY_TITLE, newValue, titleProperty);

      // update the description property
      CmsProperty descProperty =
          getCms().readPropertyObject(res, CmsPropertyDefinition.PROPERTY_DESCRIPTION, false);
      newValue = getJsp().getRequest().getParameter(PREFIX_DESCRIPTION + propertySuffix);
      writeProperty(res, CmsPropertyDefinition.PROPERTY_DESCRIPTION, newValue, descProperty);
    }

    return true;
  }
  /**
   * Returns a list item created from the resource information, differs between valid resources and
   * invalid resources.
   *
   * <p>
   *
   * @param resource the resource to create the list item from
   * @param list the list
   * @param showPermissions if to show permissions
   * @param showDateLastMod if to show the last modification date
   * @param showUserLastMod if to show the last modification user
   * @param showDateCreate if to show the creation date
   * @param showUserCreate if to show the creation date
   * @param showDateRel if to show the date released
   * @param showDateExp if to show the date expired
   * @param showState if to show the state
   * @param showLockedBy if to show the lock user
   * @param showSite if to show the site
   * @return a list item created from the resource information
   */
  protected CmsListItem createResourceListItem(
      CmsResource resource,
      CmsHtmlList list,
      boolean showPermissions,
      boolean showDateLastMod,
      boolean showUserLastMod,
      boolean showDateCreate,
      boolean showUserCreate,
      boolean showDateRel,
      boolean showDateExp,
      boolean showState,
      boolean showLockedBy,
      boolean showSite) {

    CmsListItem item = list.newItem(resource.getStructureId().toString());
    // get an initialized resource utility
    CmsResourceUtil resUtil = getWp().getResourceUtil();
    resUtil.setResource(resource);
    item.set(A_CmsListExplorerDialog.LIST_COLUMN_NAME, resUtil.getPath());
    item.set(A_CmsListExplorerDialog.LIST_COLUMN_ROOT_PATH, resUtil.getFullPath());
    item.set(A_CmsListExplorerDialog.LIST_COLUMN_TITLE, resUtil.getTitle());
    item.set(A_CmsListExplorerDialog.LIST_COLUMN_TYPE, resUtil.getResourceTypeName());
    item.set(A_CmsListExplorerDialog.LIST_COLUMN_SIZE, resUtil.getSizeString());
    if (showPermissions) {
      item.set(A_CmsListExplorerDialog.LIST_COLUMN_PERMISSIONS, resUtil.getPermissionString());
    }
    if (showDateLastMod) {
      item.set(
          A_CmsListExplorerDialog.LIST_COLUMN_DATELASTMOD,
          new Date(resource.getDateLastModified()));
    }
    if (showUserLastMod) {
      item.set(A_CmsListExplorerDialog.LIST_COLUMN_USERLASTMOD, resUtil.getUserLastModified());
    }
    if (showDateCreate) {
      item.set(A_CmsListExplorerDialog.LIST_COLUMN_DATECREATE, new Date(resource.getDateCreated()));
    }
    if (showUserCreate) {
      item.set(A_CmsListExplorerDialog.LIST_COLUMN_USERCREATE, resUtil.getUserCreated());
    }
    if (showDateRel) {
      item.set(A_CmsListExplorerDialog.LIST_COLUMN_DATEREL, new Date(resource.getDateReleased()));
    }
    if (showDateExp) {
      item.set(A_CmsListExplorerDialog.LIST_COLUMN_DATEEXP, new Date(resource.getDateExpired()));
    }
    if (showState) {
      item.set(A_CmsListExplorerDialog.LIST_COLUMN_STATE, resUtil.getStateName());
    }
    if (showLockedBy) {
      item.set(A_CmsListExplorerDialog.LIST_COLUMN_LOCKEDBY, resUtil.getLockedByName());
    }
    if (showSite) {
      item.set(A_CmsListExplorerDialog.LIST_COLUMN_SITE, resUtil.getSiteTitle());
    }
    setAdditionalColumns(item, resUtil);
    return item;
  }
  /**
   * Wrapper method for caching the result of {@link #getResources(CmsObject, Map)}.
   *
   * <p>
   *
   * @param cms the cms object
   * @param params the parameter map
   * @return the result of {@link #getResources(CmsObject, Map)}
   * @throws CmsException if something goes wrong
   */
  protected List<CmsResource> getInternalResources(CmsObject cms, Map<String, String> params)
      throws CmsException {

    synchronized (this) {
      if (m_resources == null) {
        m_resources = getResources(cms, params);
        Iterator<CmsResource> it = m_resources.iterator();
        while (it.hasNext()) {
          CmsResource resource = it.next();
          m_resCache.put(resource.getStructureId().toString(), resource);
        }
      }
    }
    return m_resources;
  }
  /** @see org.opencms.workplace.list.A_CmsListDialog#getListItems() */
  @Override
  protected List<CmsListItem> getListItems() {

    List<CmsListItem> result = new ArrayList<CmsListItem>();
    // get content
    CmsListItem item;
    int idCounter = 0;
    for (CmsResource resource : this.getResources()) {
      item = getList().newItem(resource.getRootPath());
      this.fillItem(resource, item, idCounter);
      idCounter++;
      result.add(item);
    }
    return result;
  }
  /**
   * Creates a new instance of this comparator key.
   *
   * <p>
   *
   * @param cms the current OpenCms user context
   * @param resource the resource to create the key for
   * @param dateIdentifiers the date identifiers to use for selecting the date
   * @return a new instance of this comparator key
   */
  private static CmsDateResourceComparator create(
      CmsObject cms, CmsResource resource, List<String> dateIdentifiers) {

    CmsDateResourceComparator result = new CmsDateResourceComparator();
    result.m_date = calculateDate(cms, resource, dateIdentifiers, resource.getDateCreated());
    return result;
  }
  /**
   * Checks if the resource operation is an operation on at least one folder.
   *
   * <p>
   *
   * @return true if the operation an operation on at least one folder, otherwise false
   */
  protected boolean isOperationOnFolder() {

    Iterator<String> i = getResourceList().iterator();
    while (i.hasNext()) {
      String resName = i.next();
      try {
        CmsResource curRes = getCms().readResource(resName, CmsResourceFilter.ALL);
        if (curRes.isFolder()) {
          // found a folder
          return true;
        }
      } catch (CmsException e) {
        // can usually be ignored
        if (LOG.isInfoEnabled()) {
          LOG.info(e.getLocalizedMessage());
        }
      }
    }
    return false;
  }
  /** @see java.util.Comparator#compare(java.lang.Object, java.lang.Object) */
  public int compare(CmsResource res0, CmsResource res1) {

    if (res0 == res1) {
      return 0;
    }

    CmsDateResourceComparator key0 = m_keys.get(res0.getStructureId());
    CmsDateResourceComparator key1 = m_keys.get(res1.getStructureId());

    if (key0 == null) {
      // initialize key if null
      key0 = CmsDateResourceComparator.create(m_cms, res0, m_dateIdentifiers);
      m_keys.put(res0.getStructureId(), key0);
    }
    if (key1 == null) {
      // initialize key if null
      key1 = CmsDateResourceComparator.create(m_cms, res1, m_dateIdentifiers);
      m_keys.put(res1.getStructureId(), key1);
    }

    if (m_asc) {
      // sort in ascending order
      if (key0.m_date > key1.m_date) {
        return 1;
      }
      if (key0.m_date < key1.m_date) {
        return -1;
      }
    } else {
      // sort in descending order
      if (key0.m_date > key1.m_date) {
        return -1;
      }
      if (key0.m_date < key1.m_date) {
        return 1;
      }
    }

    return 0;
  }
  /**
   * Sets the title of the dialog depending on the operation type, multiple or single operation.
   *
   * <p>
   *
   * @param singleKey the key for the single operation
   * @param multiKey the key for the multiple operation
   */
  public void setDialogTitle(String singleKey, String multiKey) {

    if (isMultiOperation()) {
      // generate title with number of selected resources and parent folder parameters
      String resCount = String.valueOf(getResourceList().size());
      String currentFolder = CmsResource.getFolderPath(getSettings().getExplorerResource());
      currentFolder = CmsStringUtil.formatResourceName(currentFolder, 40);
      Object[] params = new Object[] {resCount, currentFolder};
      setParamTitle(key(multiKey, params));
    } else {
      // generate title using the resource name as parameter for the key
      String resourceName = CmsStringUtil.formatResourceName(getParamResource(), 50);
      setParamTitle(key(singleKey, new Object[] {resourceName}));
    }
  }
  /** @see java.lang.Object#toString() */
  @Override
  public String toString() {

    StringBuffer result = new StringBuffer();
    result.append(this.getClass().getName());
    result.append("[vfsName=");
    result.append(m_vfsName);
    result.append(", rfsName=");
    result.append(m_rfsName);
    if (m_resource != null) {
      result.append(", structureId=");
      result.append(m_resource.getStructureId());
    }
    result.append("]");
    return result.toString();
  }
  /**
   * Builds the HTML for the resource list that is affected by the multi operation.
   *
   * <p>
   *
   * @return the HTML for the resource list that is affected by the multi operation
   */
  public String buildResourceList() {

    // check how many resources are selected to decide using a div or not
    boolean scroll = (getResourceList().size() > 6);

    StringBuffer result = new StringBuffer(1024);

    result.append(dialogWhiteBoxStart());

    // if the output to long, wrap it in a div
    if (scroll) {
      result.append("<div style='width: 100%; height:100px; overflow: auto;'>\n");
    }

    result.append("<table border=\"0\">\n");
    Iterator<String> i = getResourceList().iterator();
    while (i.hasNext()) {
      String resName = i.next();
      result.append("\t<tr>\n");
      result.append("\t\t<td class='textbold' style=\"vertical-align:top;\">");
      result.append(CmsResource.getName(resName));
      result.append("&nbsp;</td>\n\t\t<td style=\"vertical-align:top;\">");
      String title = null;
      try {
        // get the title property value
        title =
            getCms()
                .readPropertyObject(resName, CmsPropertyDefinition.PROPERTY_TITLE, false)
                .getValue(null);
      } catch (CmsException e) {
        // ignore this exception, title not found
      }
      if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(title)) {
        // show the title information
        result.append(title);
      }
      result.append("</td>\n\t</tr>\n");
    }
    result.append("</table>");

    // close the div if needed
    if (scroll) {
      result.append("</div>\n");
    }
    result.append(dialogWhiteBoxEnd());
    return result.toString();
  }
  /**
   * Returns a list of resources which contains no linked entries.
   *
   * <p>Links on the same resource entry are deleted from the list of resources. This method has to
   * be used after calling the method CmsObject.getResourcesInTimeRange(String, long, long);
   *
   * @param resources the list of resources which may contain links
   * @return a filtered list of resources
   */
  public static List<CmsResource> filterLinkedResources(List<CmsResource> resources) {

    List<CmsResource> filteredResources = new ArrayList<CmsResource>();
    Set<CmsUUID> addedResources = new HashSet<CmsUUID>();
    long currentTime = System.currentTimeMillis();
    Iterator<CmsResource> i = resources.iterator();

    while (i.hasNext()) {

      CmsResource currentResource = i.next();

      // filter those documents that are folders or outside the release and expire window
      if (currentResource.isFolder()
          || (currentResource.getDateReleased() > currentTime)
          || (currentResource.getDateExpired() < currentTime)) {
        // skip folders and resources outside time range
        continue;
      }

      if (CmsDocumentFactory.isIgnoredDocument(currentResource.getRootPath(), true)) {
        // this resource is ignored, skip it before checking the resource id
        continue;
      }

      CmsUUID resId = currentResource.getResourceId();

      if (!addedResources.contains(resId)) {

        // add resource to return list and ID to set
        addedResources.add(resId);
        filteredResources.add(currentResource);
      }
    }

    // clear objects to release memory
    i = null;
    addedResources = null;
    resources = null;

    return filteredResources;
  }
  /**
   * Returns the HTML for the dialog input form to comment the images.
   *
   * <p>
   *
   * @return the HTML for the dialog input form to comment the images
   */
  public String buildDialogForm() {

    StringBuffer result = new StringBuffer(16384);
    Iterator i = getImages().iterator();

    result.append("<div style=\"height: 450px; padding: 4px; overflow: auto;\">");

    while (i.hasNext()) {
      CmsResource res = (CmsResource) i.next();
      String imageName = res.getName();
      String propertySuffix = "" + imageName.hashCode();
      result.append(dialogBlockStart(imageName));
      result.append("<table border=\"0\">\n");
      result.append("<tr>\n\t<td style=\"vertical-align: top;\">");
      // create image tag
      result.append("<img src=\"");
      StringBuffer link = new StringBuffer(256);
      link.append(getCms().getSitePath(res));
      link.append(getImageScaler().toRequestParam());
      result.append(getJsp().link(link.toString()));
      result.append("\" border=\"0\" alt=\"\" width=\"");
      result.append(getImageScaler().getWidth());
      result.append("\" height=\"");
      result.append(getImageScaler().getHeight());
      result.append("\">");

      result.append("</td>\n");
      result.append("\t<td class=\"maxwidth\" style=\"vertical-align: top;\">\n");

      result.append("\t\t<table border=\"0\">\n");

      // build title property input row
      String title = "";
      try {
        title =
            getCms()
                .readPropertyObject(res, CmsPropertyDefinition.PROPERTY_TITLE, false)
                .getValue();
      } catch (CmsException e) {
        // log, should never happen
        if (LOG.isErrorEnabled()) {
          LOG.error(e.getLocalizedMessage(getLocale()));
        }
      }
      result.append("\t\t<tr>\n\t\t\t<td style=\"white-space: nowrap;\" unselectable=\"on\">");
      result.append(key(Messages.GUI_LABEL_TITLE_0));
      result.append(":</td>\n\t\t\t<td class=\"maxwidth\">");
      result.append("<input type=\"text\" class=\"maxwidth\" name=\"");
      result.append(PREFIX_TITLE);
      result.append(propertySuffix);
      result.append("\" value=\"");
      if (CmsStringUtil.isNotEmpty(title)) {
        result.append(CmsEncoder.escapeXml(title));
      }
      result.append("\">");
      result.append("</td>\n\t\t</tr>\n");

      // build description property input row
      String description = "";
      try {
        description =
            getCms()
                .readPropertyObject(res, CmsPropertyDefinition.PROPERTY_DESCRIPTION, false)
                .getValue();
      } catch (CmsException e) {
        // log, should never happen
        if (LOG.isErrorEnabled()) {
          LOG.error(e.getLocalizedMessage(getLocale()));
        }
      }
      result.append(
          "\t\t<tr>\n\t\t\t<td style=\"white-space: nowrap; vertical-align: top;\" unselectable=\"on\">");
      result.append(key(Messages.GUI_LABEL_DESCRIPTION_0));
      result.append(":</td>\n\t\t\t<td style=\"vertical-align: top; height: 110px;\">");
      result.append("<textarea rows=\"8\" class=\"maxwidth\" style=\"overflow: auto;\" name=\"");
      result.append(PREFIX_DESCRIPTION);
      result.append(propertySuffix);
      result.append("\">");
      if (CmsStringUtil.isNotEmpty(description)) {
        result.append(CmsEncoder.escapeXml(description));
      }
      result.append("</textarea>");
      result.append("</td>\n\t\t</tr>\n");

      result.append("\t\t</table>\n");

      result.append("</td>\n</tr>\n");
      result.append("</table>\n");
      result.append(dialogBlockEnd());

      if (i.hasNext()) {
        // append spacer if another entry follows
        result.append(dialogSpacer());
      }
    }

    result.append("</div>");

    return result.toString();
  }
  /**
   * Returns a list of list items from a list of resources.
   *
   * <p>
   *
   * @param parameter the collector parameter or <code>null</code> for default.
   *     <p>
   * @return a list of {@link CmsListItem} objects
   * @throws CmsException if something goes wrong
   */
  public List<CmsListItem> getListItems(String parameter) throws CmsException {

    synchronized (this) {
      if (parameter == null) {
        parameter = m_collectorParameter;
      }
      Map<String, String> params =
          CmsStringUtil.splitAsMap(
              parameter,
              I_CmsListResourceCollector.SEP_PARAM,
              I_CmsListResourceCollector.SEP_KEYVAL);
      CmsListState state = getState(params);
      List<CmsResource> resources = getInternalResources(getWp().getCms(), params);
      List<CmsListItem> ret = new ArrayList<CmsListItem>();
      if (LOG.isDebugEnabled()) {
        LOG.debug(
            Messages.get()
                .getBundle()
                .key(Messages.LOG_COLLECTOR_PROCESS_ITEMS_START_1, new Integer(resources.size())));
      }
      getWp().applyColumnVisibilities();
      CmsHtmlList list = getWp().getList();

      // check if progress should be set in the thread
      CmsProgressThread thread = null;
      int progressOffset = 0;
      if (Thread.currentThread() instanceof CmsProgressThread) {
        thread = (CmsProgressThread) Thread.currentThread();
        progressOffset = thread.getProgress();
      }

      CmsListColumnDefinition colPermissions =
          list.getMetadata().getColumnDefinition(A_CmsListExplorerDialog.LIST_COLUMN_PERMISSIONS);
      boolean showPermissions = (colPermissions.isVisible() || colPermissions.isPrintable());
      CmsListColumnDefinition colDateLastMod =
          list.getMetadata().getColumnDefinition(A_CmsListExplorerDialog.LIST_COLUMN_DATELASTMOD);
      boolean showDateLastMod = (colDateLastMod.isVisible() || colDateLastMod.isPrintable());
      CmsListColumnDefinition colUserLastMod =
          list.getMetadata().getColumnDefinition(A_CmsListExplorerDialog.LIST_COLUMN_USERLASTMOD);
      boolean showUserLastMod = (colUserLastMod.isVisible() || colUserLastMod.isPrintable());
      CmsListColumnDefinition colDateCreate =
          list.getMetadata().getColumnDefinition(A_CmsListExplorerDialog.LIST_COLUMN_DATECREATE);
      boolean showDateCreate = (colDateCreate.isVisible() || colDateCreate.isPrintable());
      CmsListColumnDefinition colUserCreate =
          list.getMetadata().getColumnDefinition(A_CmsListExplorerDialog.LIST_COLUMN_USERCREATE);
      boolean showUserCreate = (colUserCreate.isVisible() || colUserCreate.isPrintable());
      CmsListColumnDefinition colDateRel =
          list.getMetadata().getColumnDefinition(A_CmsListExplorerDialog.LIST_COLUMN_DATEREL);
      boolean showDateRel = (colDateRel.isVisible() || colDateRel.isPrintable());
      CmsListColumnDefinition colDateExp =
          list.getMetadata().getColumnDefinition(A_CmsListExplorerDialog.LIST_COLUMN_DATEEXP);
      boolean showDateExp = (colDateExp.isVisible() || colDateExp.isPrintable());
      CmsListColumnDefinition colState =
          list.getMetadata().getColumnDefinition(A_CmsListExplorerDialog.LIST_COLUMN_STATE);
      boolean showState = (colState.isVisible() || colState.isPrintable());
      CmsListColumnDefinition colLockedBy =
          list.getMetadata().getColumnDefinition(A_CmsListExplorerDialog.LIST_COLUMN_LOCKEDBY);
      boolean showLockedBy = (colLockedBy.isVisible() || colLockedBy.isPrintable());
      CmsListColumnDefinition colSite =
          list.getMetadata().getColumnDefinition(A_CmsListExplorerDialog.LIST_COLUMN_SITE);
      boolean showSite = (colSite.isVisible() || colSite.isPrintable());

      // get content
      Iterator<CmsResource> itRes = resources.iterator();
      int count = 0;
      while (itRes.hasNext()) {
        // set progress in thread
        if (thread != null) {
          count++;
          if (thread.isInterrupted()) {
            throw new CmsIllegalStateException(
                org.opencms.workplace.commons.Messages.get()
                    .container(org.opencms.workplace.commons.Messages.ERR_PROGRESS_INTERRUPTED_0));
          }
          thread.setProgress(((count * 40) / resources.size()) + progressOffset);
          thread.setDescription(
              org.opencms.workplace.commons.Messages.get()
                  .getBundle(thread.getLocale())
                  .key(
                      org.opencms.workplace.commons.Messages.GUI_PROGRESS_PUBLISH_STEP2_2,
                      new Integer(count),
                      new Integer(resources.size())));
        }

        Object obj = itRes.next();
        if (!(obj instanceof CmsResource)) {
          ret.add(getDummyListItem(list));
          continue;
        }
        CmsResource resource = (CmsResource) obj;
        CmsListItem item = m_liCache.get(resource.getStructureId().toString());
        if (item == null) {
          item =
              createResourceListItem(
                  resource,
                  list,
                  showPermissions,
                  showDateLastMod,
                  showUserLastMod,
                  showDateCreate,
                  showUserCreate,
                  showDateRel,
                  showDateExp,
                  showState,
                  showLockedBy,
                  showSite);
          m_liCache.put(resource.getStructureId().toString(), item);
        }
        ret.add(item);
      }
      CmsListMetadata metadata = list.getMetadata();
      if (metadata != null) {
        if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(state.getFilter())) {
          // filter
          ret = metadata.getSearchAction().filter(ret, state.getFilter());
        }
        if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(state.getColumn())) {
          if ((metadata.getColumnDefinition(state.getColumn()) != null)
              && metadata.getColumnDefinition(state.getColumn()).isSorteable()) {
            // sort
            I_CmsListItemComparator c =
                metadata.getColumnDefinition(state.getColumn()).getListItemComparator();
            Collections.sort(ret, c.getComparator(state.getColumn(), getWp().getLocale()));
            if (state.getOrder().equals(CmsListOrderEnum.ORDER_DESCENDING)) {
              Collections.reverse(ret);
            }
          }
        }
      }
      if (LOG.isDebugEnabled()) {
        LOG.debug(
            Messages.get()
                .getBundle()
                .key(Messages.LOG_COLLECTOR_PROCESS_ITEMS_END_1, new Integer(ret.size())));
      }
      return ret;
    }
  }
  /**
   * Calculates the date to use for comparison of this resource based on the given date identifiers.
   *
   * <p>
   *
   * @param cms the current OpenCms user context
   * @param resource the resource to create the key for
   * @param dateIdentifiers the date identifiers to use for selecting the date
   * @param defaultValue the default value to use in case no value can be calculated
   * @return the calculated date
   * @see CmsDateResourceComparator for a description about how the date identifieres are used
   */
  public static long calculateDate(
      CmsObject cms, CmsResource resource, List<String> dateIdentifiers, long defaultValue) {

    long result = 0;
    List<CmsProperty> properties = null;
    for (int i = 0, size = dateIdentifiers.size(); i < size; i++) {
      // check all configured comparisons
      String date = dateIdentifiers.get(i);
      int pos = DATE_ATTRIBUTES_LIST.indexOf(date);
      switch (pos) {
        case 0: // "dateCreated"
          result = resource.getDateCreated();
          break;
        case 1: // "dateLastModified"
          result = resource.getDateLastModified();
          break;
        case 2: // "dateContent"
          if (resource.isFile()) {
            // date content makes no sense for folders
            result = resource.getDateContent();
          }
          break;
        case 3: // "dateReleased"
          long dr = resource.getDateReleased();
          if (dr != CmsResource.DATE_RELEASED_DEFAULT) {
            // default release date must be ignored
            result = dr;
          }
          break;
        case 4: // "dateExpired"
          long de = resource.getDateExpired();
          if (de != CmsResource.DATE_EXPIRED_DEFAULT) {
            // default expiration date must be ignored
            result = de;
          }
          break;
        default:
          // of this is not an attribute, assume this is a property
          if (properties == null) {
            // we may not have to read the properties since the user may only use attributes,
            // so use lazy initializing here
            try {
              properties = cms.readPropertyObjects(resource, false);
            } catch (CmsException e) {
              // use empty list in case of an error, to avoid further re-read tries
              properties = Collections.emptyList();
            }
          }
          String propValue = CmsProperty.get(date, properties).getValue();
          if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(propValue)) {
            try {
              result = Long.parseLong(propValue.trim());
            } catch (NumberFormatException e) {
              // maybe we have better luck with the next property
            }
          }
          break;
      }
      if (result != 0) {
        // if a date value has been found, terminate the loop
        break;
      }
    }
    if (result == 0) {
      // if nothing else was found, use default
      result = defaultValue;
    }
    return result;
  }
  /**
   * Creates a list of new resources of the specified folder and filters the unwanted resources.
   *
   * <p>If the parameter categoryFolders is an empty list, all new resources are returned, otherwise
   * only those resources which are in a subfolder specified by the list.
   *
   * <p>
   *
   * @param cms the CmsObject
   * @param startFolder the root folder
   * @param startDate the start date in milliseconds
   * @param endDate the end date in milliseconds
   * @param selectedCategories list with selected categories/folders
   * @param openedCategories list with opened categories/folders
   * @return list of new resources
   */
  private static List<CmsResource> getNewResourceList(
      CmsObject cms,
      String startFolder,
      long startDate,
      long endDate,
      List<String> selectedCategories,
      List<String> openedCategories) {

    List<CmsResource> searchResult = null;
    List<CmsResource> foundResources = null;
    Set<CmsUUID> addedResources = null;

    if (LOG.isDebugEnabled()) {

      StringBuffer buf = new StringBuffer();
      for (int i = 0, n = selectedCategories.size(); i < n; i++) {
        buf.append(selectedCategories.get(i));

        if (i < (n - 1)) {
          buf.append(", ");
        }
      }

      LOG.debug("################ INPUT VALUES FOR NEW DOCUMENTS SEARCH");
      LOG.debug("startDate : " + startDate + " " + new java.util.Date(startDate).toString());
      LOG.debug("endDate : " + endDate + " " + new java.util.Date(endDate).toString());
      LOG.debug("startFolder : " + startFolder);
      LOG.debug("categories : " + buf.toString());
    }

    try {

      // get all resources in the site root which are in the time range
      CmsResourceFilter filter = CmsResourceFilter.IGNORE_EXPIRATION;
      filter = filter.addRequireLastModifiedAfter(startDate);
      filter = filter.addRequireLastModifiedBefore(endDate);
      foundResources = cms.readResources(startFolder, filter);
    } catch (CmsException e) {

      if (LOG.isErrorEnabled()) {
        LOG.error(
            "Error reading resources in time range "
                + new java.util.Date(startDate).toString()
                + " - "
                + new java.util.Date(endDate).toString()
                + " below folder "
                + startFolder,
            e);
      }
      foundResources = Collections.emptyList();
    }

    if (selectedCategories.size() == 0) {

      // return all found resources with filtered links
      searchResult = filterLinkedResources(foundResources);
    } else {

      addedResources = new HashSet<CmsUUID>();
      searchResult = new ArrayList<CmsResource>();
      long currentTime = System.currentTimeMillis();

      for (int i = 0, n = foundResources.size(); i < n; i++) {

        // analyze each resource if it has to be included in the search result

        CmsResource resource = foundResources.get(i);

        // filter those documents that are folders or outside the release and expire window
        if (resource.isFolder()
            || (resource.getDateReleased() > currentTime)
            || (resource.getDateExpired() < currentTime)) {
          // skip folders and resources outside time range
          continue;
        }

        String resourceName = cms.getRequestContext().removeSiteRoot(resource.getRootPath());
        String parentFolder = CmsResource.getParentFolder(resourceName);
        boolean addToResult = false;

        if (!selectedCategories.contains(parentFolder) && openedCategories.contains(parentFolder)) {

          // skip resources that are inside an opened, but un-selected category/folder
          continue;
        }

        // check if the parent folder of the resource is one of the selected categories/folders
        addToResult = selectedCategories.contains(parentFolder);

        if (!addToResult) {

          // check if the resource is inside a collapsed sub-tree
          // of a selected category

          int openedCategoryCount = 0;

          while (!"/".equals(parentFolder)) {

            if (openedCategories.contains(parentFolder)) {
              openedCategoryCount++;
            }

            if (selectedCategories.contains(parentFolder) && (openedCategoryCount == 0)) {

              // we found a selected parent category,
              // and it's sub-tree is collapsed
              addToResult = true;
              break;
            }

            parentFolder = CmsResource.getParentFolder(parentFolder);
          }
        }

        if (!addToResult) {

          // continue with the next resource
          continue;
        }

        if (CmsDocumentFactory.isIgnoredDocument(resourceName, true)) {
          // this resource is ignored, skip it before checking the resource id
          continue;
        }

        // check if the resource is a sibling that has already been added to the search result
        CmsUUID resourceId = resource.getResourceId();
        if (!addedResources.contains(resourceId)) {

          // add resource to the result
          addedResources.add(resourceId);
          searchResult.add(resource);
        }
      }
    }

    return searchResult;
  }