/**
   * Produce a page and/or a tool list doPage = true is best for the tabs-based portal and for RSS -
   * these think in terms of pages doPage = false is best for the portlet-style - it unrolls all of
   * the tools unless a page is marked as a popup. If the page is a popup - it is left a page and
   * marked as such. restTools = true - generate resetting tool URLs.
   *
   * @see
   *     org.sakaiproject.portal.api.PortalSiteHelper#pageListToMap(javax.servlet.http.HttpServletRequest,
   *     boolean, org.sakaiproject.site.api.Site, org.sakaiproject.site.api.SitePage,
   *     java.lang.String, java.lang.String, boolean, boolean, boolean)
   */
  public Map pageListToMap(
      HttpServletRequest req,
      boolean loggedIn,
      Site site,
      SitePage page,
      String toolContextPath,
      String portalPrefix,
      boolean doPages,
      boolean resetTools,
      boolean includeSummary) {

    Map<String, Object> theMap = new HashMap<String, Object>();

    String pageUrl =
        Web.returnUrl(
            req, "/" + portalPrefix + "/" + Web.escapeUrl(getSiteEffectiveId(site)) + "/page/");
    String toolUrl =
        Web.returnUrl(req, "/" + portalPrefix + "/" + Web.escapeUrl(getSiteEffectiveId(site)));
    if (resetTools) {
      toolUrl = toolUrl + "/tool-reset/";
    } else {
      toolUrl = toolUrl + "/tool/";
    }

    String pagePopupUrl = Web.returnUrl(req, "/page/");
    boolean showHelp = ServerConfigurationService.getBoolean("display.help.menu", true);
    String iconUrl = "";
    try {
      if (site.getIconUrlFull() != null) iconUrl = new URI(site.getIconUrlFull()).toString();
    } catch (URISyntaxException uex) {
      log.debug("Icon URL is invalid: " + site.getIconUrlFull());
    }

    boolean published = site.isPublished();
    String type = site.getType();

    theMap.put("siteId", site.getId());
    theMap.put("pageNavPublished", Boolean.valueOf(published));
    theMap.put("pageNavType", type);
    theMap.put("pageNavIconUrl", iconUrl);
    String htmlInclude = site.getProperties().getProperty(PROP_HTML_INCLUDE);
    if (htmlInclude != null) theMap.put("siteHTMLInclude", htmlInclude);

    // theMap.put("pageNavSitToolsHead",
    // Web.escapeHtml(rb.getString("sit_toolshead")));

    // order the pages based on their tools and the tool order for the
    // site type
    // List pages = site.getOrderedPages();
    List pages = getPermittedPagesInOrder(site);

    List<Map> l = new ArrayList<Map>();

    String addMoreToolsUrl = null;
    for (Iterator i = pages.iterator(); i.hasNext(); ) {

      SitePage p = (SitePage) i.next();
      // check if current user has permission to see page
      // we will draw page button if it have permission to see at least
      // one tool on the page
      List<ToolConfiguration> pTools = p.getTools();
      ToolConfiguration firstTool = null;
      String toolsOnPage = null;

      boolean current = (page != null && p.getId().equals(page.getId()) && !p.isPopUp());
      String alias = lookupPageToAlias(site.getId(), p);
      String pagerefUrl = pageUrl + Web.escapeUrl((alias != null) ? alias : p.getId());

      if (doPages || p.isPopUp()) {
        Map<String, Object> m = new HashMap<String, Object>();
        StringBuffer desc = new StringBuffer();

        boolean hidden = false;
        if (pTools != null && pTools.size() > 0) {
          firstTool = pTools.get(0);
          hidden = true; // Only set the page to hidden when we have tools that might un-hide it.
          Iterator<ToolConfiguration> tools = pTools.iterator();
          // get the tool descriptions for this page, typically only one per page, execpt for the
          // Home page
          int tCount = 0;
          while (tools.hasNext()) {
            ToolConfiguration t = tools.next();
            if (hidden && !isHidden(t)) {
              hidden = false;
            }
            if (tCount > 0) {
              desc.append(" | ");
            }
            if (t.getTool() == null) continue;
            desc.append(t.getTool().getDescription());
            tCount++;
            if ("sakai.siteinfo".equals(t.getToolId())) {
              addMoreToolsUrl =
                  Web.returnUrl(
                      req,
                      "/site/"
                          + Web.escapeUrl(site.getId())
                          + "/page/"
                          + Web.escapeUrl(p.getId())
                          + "?sakai_action=doMenu_edit_site_tools&panel=Shortcut");
            }
          }
          // Won't work with mutliple tools per page
          if (tCount > 1) addMoreToolsUrl = null;
        }

        boolean siteUpdate = SecurityService.unlock("site.upd", site.getReference());
        if (!siteUpdate) addMoreToolsUrl = null;

        if (!ServerConfigurationService.getBoolean("portal.experimental.addmoretools", false))
          addMoreToolsUrl = null;

        m.put("isPage", Boolean.valueOf(true));
        m.put("current", Boolean.valueOf(current));
        m.put("ispopup", Boolean.valueOf(p.isPopUp()));
        m.put("pagePopupUrl", pagePopupUrl);
        m.put("pageTitle", Web.escapeHtml(p.getTitle()));
        m.put("jsPageTitle", Web.escapeJavascript(p.getTitle()));
        m.put("pageId", Web.escapeUrl(p.getId()));
        m.put("jsPageId", Web.escapeJavascript(p.getId()));
        m.put("pageRefUrl", pagerefUrl);

        // TODO: Should have Web.escapeHtmlAttribute()
        String description = desc.toString().replace("\"", "&quot;");
        m.put("description", description);
        m.put("hidden", Boolean.valueOf(hidden));
        // toolsOnPage is always null
        // if (toolsOnPage != null) m.put("toolsOnPage", toolsOnPage);
        if (includeSummary) summarizePage(m, site, p);
        if (firstTool != null) {
          String menuClass = firstTool.getToolId();
          menuClass = "icon-" + menuClass.replace('.', '-');
          m.put("menuClass", menuClass);
          Properties tmp = firstTool.getConfig();
          if (tmp != null) {
            String mc = tmp.getProperty(PROP_MENU_CLASS);
            if (mc != null && mc.length() > 0) m.put("menuClassOverride", mc);
          }
        } else {
          m.put("menuClass", "icon-default-tool");
        }
        m.put("pageProps", createPageProps(p));
        // this is here to allow the tool reorder to work
        m.put("_sitePage", p);
        l.add(m);
        continue;
      }

      // Loop through the tools again and Unroll the tools
      Iterator iPt = pTools.iterator();

      while (iPt.hasNext()) {
        ToolConfiguration placement = (ToolConfiguration) iPt.next();

        Tool tool = placement.getTool();
        if (tool != null) {
          String toolrefUrl = toolUrl + Web.escapeUrl(placement.getId());

          Map<String, Object> m = new HashMap<String, Object>();
          m.put("isPage", Boolean.valueOf(false));
          m.put("toolId", Web.escapeUrl(placement.getId()));
          m.put("jsToolId", Web.escapeJavascript(placement.getId()));
          m.put("toolRegistryId", placement.getToolId());
          m.put("toolTitle", Web.escapeHtml(placement.getTitle()));
          m.put("jsToolTitle", Web.escapeJavascript(placement.getTitle()));
          m.put("toolrefUrl", toolrefUrl);
          String menuClass = placement.getToolId();
          menuClass = "icon-" + menuClass.replace('.', '-');
          m.put("menuClass", menuClass);
          Properties tmp = placement.getConfig();
          if (tmp != null) {
            String mc = tmp.getProperty(PROP_MENU_CLASS);
            if (mc != null && mc.length() > 0) m.put("menuClassOverride", mc);
          }
          // this is here to allow the tool reorder to work if requried.
          m.put("_placement", placement);
          l.add(m);
        }
      }
    }
    PageFilter pageFilter = portal.getPageFilter();
    if (pageFilter != null) {
      l = pageFilter.filterPlacements(l, site);
    }

    if (addMoreToolsUrl != null) {
      theMap.put("pageNavAddMoreToolsUrl", addMoreToolsUrl);
      theMap.put("pageNavCanAddMoreTools", true);
    } else {
      theMap.put("pageNavCanAddMoreTools", false);
    }

    theMap.put("pageNavTools", l);
    theMap.put(
        "pageMaxIfSingle",
        ServerConfigurationService.getBoolean("portal.experimental.maximizesinglepage", false));
    theMap.put("pageNavToolsCount", Integer.valueOf(l.size()));

    String helpUrl = ServerConfigurationService.getHelpUrl(null);
    theMap.put("pageNavShowHelp", Boolean.valueOf(showHelp));
    theMap.put("pageNavHelpUrl", helpUrl);
    theMap.put("helpMenuClass", "icon-sakai-help");
    theMap.put("subsiteClass", "icon-sakai-subsite");

    // theMap.put("pageNavSitContentshead",
    // Web.escapeHtml(rb.getString("sit_contentshead")));

    // Display presence? Global property display.users.present may be always / never / true / false
    // If true or false, the value may be overriden by the site property display-users-present
    // which may be true or false.

    boolean showPresence;
    String globalShowPresence =
        ServerConfigurationService.getString("display.users.present", "true");

    if ("never".equals(globalShowPresence)) {
      showPresence = false;
    } else if ("always".equals(globalShowPresence)) {
      showPresence = true;
    } else {
      String showPresenceSite = site.getProperties().getProperty("display-users-present");

      if (showPresenceSite == null) {
        showPresence = Boolean.valueOf(globalShowPresence).booleanValue();
      } else {
        showPresence = Boolean.valueOf(showPresenceSite).booleanValue();
      }
    }

    // Check to see if this is a my workspace site, and if so, whether presence is disabled
    if (showPresence
        && SiteService.isUserSite(site.getId())
        && !ServerConfigurationService.getBoolean("display.users.present.myworkspace", false))
      showPresence = false;

    String presenceUrl = Web.returnUrl(req, "/presence/" + Web.escapeUrl(site.getId()));

    // theMap.put("pageNavSitPresenceTitle",
    // Web.escapeHtml(rb.getString("sit_presencetitle")));
    // theMap.put("pageNavSitPresenceFrameTitle",
    // Web.escapeHtml(rb.getString("sit_presenceiframetit")));
    theMap.put("pageNavShowPresenceLoggedIn", Boolean.valueOf(showPresence && loggedIn));
    theMap.put("pageNavPresenceUrl", presenceUrl);

    // Retrieve whether or not we are to put presence in a frame
    theMap.put(
        "pageNavPresenceIframe",
        Boolean.valueOf(
            ServerConfigurationService.getBoolean("display.users.present.iframe", false)));
    theMap.put(
        "sakaiPresenceTimeDelay",
        Integer.valueOf(
            ServerConfigurationService.getInt("display.users.present.time.delay", 3000)));

    return theMap;
  }
  /**
   * Explode a site into a map suitable for use in the map
   *
   * @see
   *     org.sakaiproject.portal.api.PortalSiteHelper#convertSiteToMap(javax.servlet.http.HttpServletRequest,
   *     org.sakaiproject.site.api.Site, java.lang.String, java.lang.String, java.lang.String,
   *     boolean, boolean, boolean, boolean, java.lang.String, boolean)
   */
  public Map convertSiteToMap(
      HttpServletRequest req,
      Site s,
      String prefix,
      String currentSiteId,
      String myWorkspaceSiteId,
      boolean includeSummary,
      boolean expandSite,
      boolean resetTools,
      boolean doPages,
      String toolContextPath,
      boolean loggedIn) {
    if (s == null) return null;
    Map<String, Object> m = new HashMap<String, Object>();

    // In case the effective is different than the actual site
    String effectiveSite = getSiteEffectiveId(s);

    boolean isCurrentSite =
        currentSiteId != null
            && (s.getId().equals(currentSiteId) || effectiveSite.equals(currentSiteId));
    m.put("isCurrentSite", Boolean.valueOf(isCurrentSite));
    m.put(
        "isMyWorkspace",
        Boolean.valueOf(
            myWorkspaceSiteId != null
                && (s.getId().equals(myWorkspaceSiteId)
                    || effectiveSite.equals(myWorkspaceSiteId))));
    int siteTitleMaxLength = ServerConfigurationService.getInt("site.title.maxlength", 25);
    String titleStr = s.getTitle();
    String fullTitle = titleStr;
    if (titleStr != null) {
      titleStr = titleStr.trim();
      if (titleStr.length() > siteTitleMaxLength && siteTitleMaxLength >= 10) {
        titleStr = titleStr.substring(0, siteTitleMaxLength - 4) + " ...";
      } else if (titleStr.length() > siteTitleMaxLength) {
        titleStr = titleStr.substring(0, siteTitleMaxLength);
      }
      titleStr = titleStr.trim();
    }
    m.put("siteTitle", Web.escapeHtml(titleStr));
    m.put("fullTitle", Web.escapeHtml(fullTitle));
    m.put("siteDescription", Web.escapeHtml(s.getDescription()));
    m.put("shortDescription", Web.escapeHtml(s.getShortDescription()));
    String siteUrl = Web.serverUrl(req) + ServerConfigurationService.getString("portalPath") + "/";
    if (prefix != null) siteUrl = siteUrl + prefix + "/";
    // siteUrl = siteUrl + Web.escapeUrl(siteHelper.getSiteEffectiveId(s));
    m.put("siteUrl", siteUrl + Web.escapeUrl(getSiteEffectiveId(s)));
    m.put("siteType", s.getType());
    m.put("siteId", s.getId());

    // TODO: This should come from the site neighbourhood.
    ResourceProperties rp = s.getProperties();
    String ourParent = rp.getProperty(PROP_PARENT_ID);
    // We are not really a child unless the parent exists
    // And we have a valid pwd
    boolean isChild = false;

    // Get the current site hierarchy
    if (ourParent != null && isCurrentSite) {
      List<Site> pwd = getPwd(s, ourParent);
      if (pwd != null) {
        List<Map> l = new ArrayList<Map>();
        for (int i = 0; i < pwd.size(); i++) {
          Site site = pwd.get(i);
          // System.out.println("PWD["+i+"]="+site.getId()+"
          // "+site.getTitle());
          Map<String, Object> pm = new HashMap<String, Object>();
          pm.put("siteTitle", Web.escapeHtml(site.getTitle()));
          pm.put("siteUrl", siteUrl + Web.escapeUrl(getSiteEffectiveId(site)));
          l.add(pm);
          isChild = true;
        }
        if (l.size() > 0) m.put("pwd", l);
      }
    }

    // If we are a child and have a non-zero length, pwd
    // show breadcrumbs
    if (isChild) {
      m.put("isChild", Boolean.valueOf(isChild));
      m.put("parentSite", ourParent);
    }

    if (includeSummary) {
      summarizeTool(m, s, "sakai.announce");
    }
    if (expandSite) {
      Map pageMap =
          pageListToMap(
              req,
              loggedIn,
              s, /* SitePage */
              null,
              toolContextPath,
              prefix,
              doPages,
              resetTools,
              includeSummary);
      m.put("sitePages", pageMap);
    }

    return m;
  }