VClassGroupSearchLink(String querytext, VClassGroup classgroup) {
   super(
       classgroup.getPublicName(),
       "/search",
       "querytext",
       querytext,
       "classgroup",
       classgroup.getURI());
 }
  private String addVClassDataToResultsList(
      WebappDaoFactory wadf, VClass vcw, int position, String ontologyUri, int counter) {
    String tempString = "";
    if (ontologyUri == null
        || ((vcw.getNamespace() != null) && (vcw.getNamespace().equals(ontologyUri)))) {
      // first if statement ensures that the first class begins with correct format
      if (counter < 1 && position < 1) {
        tempString += "{ \"name\": ";
      } else if (position == previous_posn) {
        tempString += "}, { \"name\": ";
      } else if (position > previous_posn) {
        tempString += " { \"name\": ";
      } else if (position < previous_posn) {
        tempString += "}, { \"name\": ";
      }
      try {
        tempString +=
            JSONUtils.quote(
                    "<a href='vclassEdit?uri="
                        + URLEncoder.encode(vcw.getURI(), "UTF-8")
                        + "'>"
                        + vcw.getPickListName()
                        + "</a>")
                + ", ";
      } catch (Exception e) {
        tempString +=
            JSONUtils.quote(((vcw.getPickListName() == null) ? "" : vcw.getPickListName())) + ", ";
      }

      String shortDef = ((vcw.getShortDef() == null) ? "" : vcw.getShortDef());
      tempString += "\"data\": { \"shortDef\": " + JSONUtils.quote(shortDef) + ", ";

      // Get group name if it exists
      VClassGroupDao groupDao = wadf.getVClassGroupDao();
      String groupURI = vcw.getGroupURI();
      String groupName = null;
      VClassGroup classGroup = null;
      if (groupURI != null) {
        classGroup = groupDao.getGroupByURI(groupURI);
        if (classGroup != null) {
          groupName = classGroup.getPublicName();
        }
      }
      tempString +=
          "\"classGroup\": " + JSONUtils.quote((groupName == null) ? "" : groupName) + ", ";
      // Get ontology name
      OntologyDao ontDao = wadf.getOntologyDao();
      String ontName = vcw.getNamespace();
      Ontology ont = ontDao.getOntologyByURI(ontName);
      if (ont != null && ont.getName() != null) {
        ontName = ont.getName();
      }
      tempString +=
          "\"ontology\": "
              + JSONUtils.quote((ontName == null) ? "" : ontName)
              + "}, \"children\": [";

      previous_posn = position;
    }
    return tempString;
  }
  @Override
  protected ResponseValues processRequest(VitroRequest vreq) {
    // There may be other non-html formats in the future
    Format format = getFormat(vreq);
    boolean wasXmlRequested = Format.XML == format;
    log.debug("xml was the requested format");
    boolean wasHtmlRequested = !wasXmlRequested;

    try {
      Portal portal = vreq.getPortal();
      PortalFlag portalFlag = vreq.getPortalFlag();

      // make sure an IndividualDao is available
      if (vreq.getWebappDaoFactory() == null
          || vreq.getWebappDaoFactory().getIndividualDao() == null) {
        log.error("Could not get webappDaoFactory or IndividualDao");
        throw new Exception("Could not access model.");
      }
      IndividualDao iDao = vreq.getWebappDaoFactory().getIndividualDao();
      VClassGroupDao grpDao = vreq.getWebappDaoFactory().getVClassGroupDao();
      VClassDao vclassDao = vreq.getWebappDaoFactory().getVClassDao();
      String alphaFilter = vreq.getParameter("alpha");

      int startIndex = 0;
      try {
        startIndex = Integer.parseInt(vreq.getParameter("startIndex"));
      } catch (Throwable e) {
        startIndex = 0;
      }
      log.debug("startIndex is " + startIndex);

      int hitsPerPage = defaultHitsPerPage;
      try {
        hitsPerPage = Integer.parseInt(vreq.getParameter("hitsPerPage"));
      } catch (Throwable e) {
        hitsPerPage = defaultHitsPerPage;
      }
      log.debug("hitsPerPage is " + hitsPerPage);

      int maxHitSize = defaultMaxSearchSize;
      if (startIndex >= defaultMaxSearchSize - hitsPerPage)
        maxHitSize = startIndex + defaultMaxSearchSize;
      if (alphaFilter != null) {
        maxHitSize = maxHitSize * 2;
        hitsPerPage = maxHitSize;
      }
      log.debug("maxHitSize is " + maxHitSize);

      String qtxt = vreq.getParameter(VitroQuery.QUERY_PARAMETER_NAME);
      Analyzer analyzer = getAnalyzer(getServletContext());

      Query query = null;
      try {
        query = getQuery(vreq, portalFlag, analyzer, qtxt);
        log.debug("query for '" + qtxt + "' is " + query.toString());
      } catch (ParseException e) {
        return doBadQuery(portal, qtxt, format);
      }

      IndexSearcher searcherForRequest = LuceneIndexFactory.getIndexSearcher(getServletContext());

      TopDocs topDocs = null;
      try {
        topDocs = searcherForRequest.search(query, null, maxHitSize);
      } catch (Throwable t) {
        log.error("in first pass at search: " + t);
        // this is a hack to deal with odd cases where search and index threads interact
        try {
          wait(150);
          topDocs = searcherForRequest.search(query, null, maxHitSize);
        } catch (Exception ex) {
          log.error(ex);
          String msg = makeBadSearchMessage(qtxt, ex.getMessage());
          if (msg == null) {
            msg = "The search request contained errors.";
          }
          return doFailedSearch(msg, qtxt, format);
        }
      }

      if (topDocs == null || topDocs.scoreDocs == null) {
        log.error("topDocs for a search was null");
        String msg = "The search request contained errors.";
        return doFailedSearch(msg, qtxt, format);
      }

      int hitsLength = topDocs.scoreDocs.length;
      if (hitsLength < 1) {
        return doNoHits(qtxt, format);
      }
      log.debug("found " + hitsLength + " hits");

      int lastHitToShow = 0;
      if ((startIndex + hitsPerPage) > hitsLength) {
        lastHitToShow = hitsLength;
      } else {
        lastHitToShow = startIndex + hitsPerPage - 1;
      }

      List<Individual> beans = new LinkedList<Individual>();
      for (int i = startIndex; i < topDocs.scoreDocs.length; i++) {
        try {
          if ((i >= startIndex) && (i <= lastHitToShow)) {
            Document doc = searcherForRequest.doc(topDocs.scoreDocs[i].doc);
            String uri = doc.get(Entity2LuceneDoc.term.URI);
            Individual ent = new IndividualImpl();
            ent.setURI(uri);
            ent = iDao.getIndividualByURI(uri);
            if (ent != null) beans.add(ent);
          }
        } catch (Exception e) {
          log.error("problem getting usable Individuals from search " + "hits" + e.getMessage());
        }
      }

      ParamMap pagingLinkParams = new ParamMap();
      pagingLinkParams.put("querytext", qtxt);
      pagingLinkParams.put("hitsPerPage", String.valueOf(hitsPerPage));

      if (wasXmlRequested) {
        pagingLinkParams.put(XML_REQUEST_PARAM, "1");
      }

      /* Start putting together the data for the templates */

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

      String classGroupParam = vreq.getParameter("classgroup");
      boolean classGroupFilterRequested = false;
      if (!StringUtils.isEmpty(classGroupParam)) {
        VClassGroup grp = grpDao.getGroupByURI(classGroupParam);
        classGroupFilterRequested = true;
        if (grp != null && grp.getPublicName() != null)
          body.put("classGroupName", grp.getPublicName());
      }

      String typeParam = vreq.getParameter("type");
      boolean typeFiltereRequested = false;
      if (!StringUtils.isEmpty(typeParam)) {
        VClass type = vclassDao.getVClassByURI(typeParam);
        typeFiltereRequested = true;
        if (type != null && type.getName() != null) body.put("typeName", type.getName());
      }

      /* Add classgroup and type refinement links to body */
      if (wasHtmlRequested) {
        // Search request includes no classgroup and no type, so add classgroup search refinement
        // links.
        if (!classGroupFilterRequested && !typeFiltereRequested) {
          List<VClassGroup> classgroups = getClassGroups(grpDao, topDocs, searcherForRequest);
          List<VClassGroupSearchLink> classGroupLinks =
              new ArrayList<VClassGroupSearchLink>(classgroups.size());
          for (VClassGroup vcg : classgroups) {
            if (vcg.getPublicName() != null) {
              classGroupLinks.add(new VClassGroupSearchLink(qtxt, vcg));
            }
          }
          body.put("classGroupLinks", classGroupLinks);

          // Search request is for a classgroup, so add rdf:type search refinement links
          // but try to filter out classes that are subclasses
        } else if (classGroupFilterRequested && !typeFiltereRequested) {
          List<VClass> vClasses = getVClasses(vclassDao, topDocs, searcherForRequest);
          List<VClassSearchLink> vClassLinks = new ArrayList<VClassSearchLink>(vClasses.size());
          for (VClass vc : vClasses) {
            vClassLinks.add(new VClassSearchLink(qtxt, vc));
          }
          body.put("classLinks", vClassLinks);
          pagingLinkParams.put("classgroup", classGroupParam);

          // This case is never displayed
        } else if (!StringUtils.isEmpty(alphaFilter)) {
          body.put("alphas", getAlphas(topDocs, searcherForRequest));
          alphaSortIndividuals(beans);
        } else {
          pagingLinkParams.put("type", typeParam);
        }
      }

      // Convert search result individuals to template model objects
      body.put(
          "individuals", ListedIndividualTemplateModel.getIndividualTemplateModelList(beans, vreq));

      body.put("querytext", qtxt);
      body.put("title", qtxt + " - " + portal.getAppName() + " Search Results");

      body.put("hitsLength", hitsLength);
      body.put("startIndex", startIndex);

      body.put(
          "pagingLinks",
          getPagingLinks(
              startIndex,
              hitsPerPage,
              hitsLength,
              maxHitSize,
              vreq.getServletPath(),
              pagingLinkParams));

      if (startIndex != 0) {
        body.put(
            "prevPage",
            getPreviousPageLink(startIndex, hitsPerPage, vreq.getServletPath(), pagingLinkParams));
      }
      if (startIndex < (hitsLength - hitsPerPage)) {
        body.put(
            "nextPage",
            getNextPageLink(startIndex, hitsPerPage, vreq.getServletPath(), pagingLinkParams));
      }

      String template = templateTable.get(format).get(Result.PAGED);

      return new TemplateResponseValues(template, body);
    } catch (Throwable e) {
      return doSearchError(e, format);
    }
  }