/**
   * Main method.
   *
   * <p>Most of the work is done in getHierarchy. This method mainly checks that the parameters are
   * the right number and sets the format and recurse fields.
   *
   * <p>
   *
   * @see
   *     #getHierarchyData(HttpServletRequest,SimpleServletSupport,HasRelationships,boolean,boolean,Set)
   */
  public void execute(
      HttpServletRequest request, HttpServletResponse response, SimpleServletSupport support)
      throws IOException, ServletException {
    super.execute(request, response, support);

    if (VERBOSE) {
      System.out.println("BEGIN hierarchy at " + support.getAgentIdentifier());
    }

    if (testing) {
      if (request.getRequestURI().indexOf("PlanePacker") != -1) {
        try {
          Thread.sleep(30000);
        } catch (Exception e) {
        }
      }
    }

    // generate our response.
    getHierarchy(
        response.getOutputStream(),
        request,
        support,
        format,
        recurse,
        allRelationships,
        visitedOrgs);

    if (VERBOSE) {
      System.out.println("FINISHED hierarchy at " + support.getAgentIdentifier());
    }
  }
  protected void recurseOnSubords(
      Set recurseSubOrgSet,
      HttpServletRequest request,
      SimpleServletSupport support,
      boolean allRelationships,
      Set visitedOrgs,
      HierarchyData hd) {
    for (Iterator iter = recurseSubOrgSet.iterator(); iter.hasNext(); ) {
      String subOrgName = (String) iter.next();
      // fetch the sub's data

      HierarchyData subHD = null;
      int tries = 5;
      long[] timeToWait = new long[] {32000, 16000, 8000, 4000, 2000};
      while (subHD == null && tries-- > 0) {
        subHD = fetchForSubordinate(request, support, subOrgName, allRelationships, visitedOrgs);
        if (subHD == null) {
          if (VERBOSE && tries > 1) {
            System.out.println(
                "At "
                    + new Date()
                    + " In "
                    + support.getAgentIdentifier()
                    + ", fetch hierarchy from "
                    + subOrgName
                    + " returned null, retry in "
                    + timeToWait[tries]
                    + " millis.");
          }

          synchronized (this) {
            try {
              wait(timeToWait[tries]);
            } catch (Exception e) {
              System.out.println("got exception " + e);
            }
          }
        }
      }

      if (VERBOSE && (subHD == null)) {
        System.out.println(
            "In "
                + support.getAgentIdentifier()
                + ", fetch hierarchy from "
                + subOrgName
                + " returned null.");
      }

      // take Orgs from sub's hierarchy data
      int nSubHD = ((subHD != null) ? subHD.numOrgs() : 0);
      for (int i = 0; i < nSubHD; i++) {
        hd.addOrgData(subHD.getOrgDataAt(i));
      }
    }
  }
  /**
   * Fetch HierarchyData and write to output.
   *
   * <p>Main work is done by getHierarchyData, which returns a HierarchyData object.
   *
   * <p>Output format is either data, xml, or html
   *
   * @see #getHierarchyData
   */
  protected void getHierarchy(
      OutputStream out,
      HttpServletRequest request,
      SimpleServletSupport support,
      int format,
      boolean recurse,
      boolean allRelationships,
      Set visitedOrgs) {
    // get self org
    HasRelationships selfOrg = getSelfOrg(support);
    if (selfOrg == null) {
      throw new RuntimeException("No self org?");
    }

    // get hierarchy data
    try {
      HierarchyData hd =
          getHierarchyData(request, support, selfOrg, recurse, allRelationships, visitedOrgs);

      writeResponse(hd, out, request, support, format, allRelationships);
    } catch (Exception e) {
      System.err.println(
          "Got exception " + e + " getting hierarchy data for " + support.getAgentIdentifier());
      e.printStackTrace();
    }
  }
 /** get the self organization. */
 protected HasRelationships getSelfOrg(SimpleServletSupport support) {
   // get self org
   Collection col = support.queryBlackboard(selfOrgP);
   if ((col != null) && (col.size() == 1)) {
     Iterator iter = col.iterator();
     HasRelationships org = (HasRelationships) iter.next();
     return org;
   } else {
     return null;
   }
 }
  /**
   * Writes html with the list of found agents across the top, with links to tables below for each
   * agent. The tables show each agents relationships to other agents. There are links in those
   * tables too, to the other referenced agents.
   */
  protected void writeResponse(
      XMLable result,
      OutputStream out,
      HttpServletRequest request,
      SimpleServletSupport support,
      int format,
      boolean allRelationships) {
    if ((format == FORMAT_HTML) && allRelationships) {
      HierarchyData data = (HierarchyData) result;
      if (VERBOSE)
        System.out.println(
            "HierarchyWorker.writeResponse - got data for " + data.numOrgs() + " orgs");
      PrintWriter writer = new PrintWriter(out);
      writer.println(
          "<HTML><HEAD>\n<TITLE>"
              + getPrefix()
              + support.getAgentIdentifier()
              + "</TITLE>\n"
              + "</HEAD><BODY>\n"
              + "<H2><CENTER>"
              + getPrefix()
              + support.getAgentIdentifier()
              + "</CENTER></H2><p><pre>\n");
      writer.flush();

      writer.println(
          "<a name=\"top\"/>" + "<TABLE align=center border=0 cellPadding=1 cellSpacing=1>");
      boolean rowEnded = false;
      int k = 0;
      data.sortOrgs();
      for (; k < data.numOrgs(); k++) {
        Organization org = data.getOrgDataAt(k);
        if ((k % AGENTS_IN_ROW) == 0) {
          writer.println("<TR>");
          rowEnded = false;
        }
        writer.println(
            "<TD><a href=\"#" + org.getPrettyName() + "\"/>" + org.getPrettyName() + "</a></TD>");
        if ((k % AGENTS_IN_ROW) == AGENTS_IN_ROW - 1) {
          writer.println("</TR>");
          rowEnded = true;
        }
      }
      for (int i = (k % AGENTS_IN_ROW); i < AGENTS_IN_ROW; i++) writer.print("<TD></TD>");
      if (!rowEnded) writer.println("</TR>");
      writer.println("</TABLE><P/><P/><br/>");

      for (int i = 0; i < data.numOrgs(); i++) {
        Organization org = data.getOrgDataAt(i);
        writer.println(
            "<P>Agent relationships for <B><a name=\""
                + org.getPrettyName()
                + "\" />"
                + org.getPrettyName()
                + "</B>&nbsp;<a href=\"#top\">[top]</a></P>");
        writer.println("<TABLE align=center border=1 cellPadding=1 cellSpacing=1");
        writer.println("width=75% bordercolordark=#660000 bordercolorlight=#cc9966>");
        writer.println("<TR>");
        // writer.println("<TD width=\"25%\"> <FONT color=mediumblue ><B>Agent</FONT></B> </TD>");
        writer.println(
            "<TD width=\"25%\"> <FONT color=mediumblue ><B>Assigned Agent</FONT></B></TD>");
        writer.println("<TD width=\"75%\"> <FONT color=mediumblue ><B>Role </FONT></B></TD>");
        writer.println("</TR>");

        List relations = org.getRelations();
        Collections.sort(relations);
        for (Iterator iter = relations.iterator(); iter.hasNext(); ) {
          Organization.OrgRelation relation = (Organization.OrgRelation) iter.next();
          String relatedOrg = relation.getRelatedOrg();
          writer.println(
              "<TR><TD><a href=\"#"
                  + relatedOrg
                  + "\">"
                  + relatedOrg
                  + "</a></TD><TD>"
                  + relation.getName()
                  + "</TD></TR>");
        }
        writer.println("</TABLE><P>");
      }
      writer.println("\n</BODY></HTML>\n");
      writer.flush();
    } else {
      try {
        writeResponse(result, out, request, support, format);
      } catch (Exception e) {
        System.err.println(
            "Got exception " + e + " writing out response for " + support.getAgentIdentifier());
        e.printStackTrace();
      }
    }
  }
  /**
   * recursion happens here -- for each subOrgName subordinate, a new servlet in the target agent
   * will be executed
   */
  protected HierarchyData fetchForSubordinate(
      HttpServletRequest request,
      SimpleServletSupport support,
      String subOrgName,
      boolean allRelationships,
      Set visitedOrgs) {
    HierarchyData hd = null;
    InputStream is = null;
    ObjectInputStream ois = null;

    try {
      // build URL for remote connection
      StringBuffer buf = new StringBuffer();
      buf.append("http://");
      buf.append(request.getServerName());
      buf.append(":");
      buf.append(request.getServerPort());
      buf.append("/$");
      buf.append(subOrgName);
      buf.append(support.getPath());
      buf.append("?data=true&recurse=true&visitedOrgs=");
      for (Iterator iter = visitedOrgs.iterator(); iter.hasNext(); ) {
        buf.append(iter.next());
        if (iter.hasNext()) buf.append(",");
      }
      if (allRelationships) buf.append("&allRelationships=true");

      String url = buf.toString();

      if (VERBOSE) {
        System.out.println(
            "At "
                + new Date()
                + " - in "
                + support.getAgentIdentifier()
                + ", fetch hierarchy from "
                + subOrgName
                + ", URL:\n"
                + url);
      }

      // open connection
      URL myURL = new URL(url);
      URLConnection myConnection = myURL.openConnection();
      is = myConnection.getInputStream();
      ois = new ObjectInputStream(is);

      // read single HierarchyData Object from subordinate
      hd = (HierarchyData) ois.readObject();

      if (VERBOSE) {
        System.out.println(
            "In "
                + support.getAgentIdentifier()
                + ", got "
                + ((hd != null) ? ("hierarchy[" + hd.numOrgs() + "]") : ("null"))
                + " from "
                + subOrgName);
      }

    } catch (StreamCorruptedException sce) {
      if (VERBOSE) {
        System.err.println("In " + support.getAgentIdentifier() + ", got exception : ");
        sce.printStackTrace();
      }
    } catch (FileNotFoundException fnf) {
      if (!allRelationships || true) {
        System.err.println("In " + support.getAgentIdentifier() + ", got exception : ");
        fnf.printStackTrace();
      }
    } catch (Exception e) {
      System.err.println("In " + support.getAgentIdentifier() + ", got exception : ");
      e.printStackTrace();
    } finally {
      try {
        if (ois != null) ois.close();
        if (is != null) is.close();
      } catch (Exception e) {
      }
    }

    return hd;
  }