/** ***************************************************************************** */
  public String toXML() {
    StringBuilder xml = new StringBuilder("<offer ");

    xml.append("initiator=\"").append(getInitiatorString()).append("\">");

    // the rest of the xml is only needed if it's system initiated
    if (isSystemInitiated()) {
      xml.append("<distributionSet>");
      xml.append("<initialSet>");

      if (_participants != null) {
        for (Participant p : _participants) {
          xml.append("<participant>").append(p.getID()).append("</participant>");
        }
      }
      if (_roles != null) {
        for (Role r : _roles) {
          xml.append("<role>").append(r.getID()).append("</role>");
        }
      }
      if (_dynParams != null) {
        for (DynParam p : _dynParams) {
          xml.append(p.toXML());
        }
      }

      xml.append("</initialSet>");

      if ((_filters != null) && (!_filters.isEmpty())) {
        xml.append("<filters>");
        for (AbstractFilter filter : _filters) {
          xml.append(filter.toXML());
        }
        xml.append("</filters>");
      }

      if ((_constraints != null) && (!_constraints.isEmpty())) {
        xml.append("<constraints>");
        for (AbstractConstraint constraint : _constraints) {
          xml.append(constraint.toXML());
        }
        xml.append("</constraints>");
      }

      xml.append("</distributionSet>");

      if (_familiarParticipantTask != null) {
        xml.append("<familiarParticipant taskID=\"");
        xml.append(_familiarParticipantTask).append("\"/>");
      }
    }

    xml.append("</offer>");
    return xml.toString();
  }
  /**
   * Takes the initial distribution set of participants, then expands any roles and/or dynamic
   * parameters to their 'set of participants' equivalents, then applies the specified filters
   * and/or constraints, and returns the final distribution set of participants.
   *
   * @param wir the workitem being offered
   * @return the final distribution set of Participant objects
   */
  public Set<Participant> performOffer(WorkItemRecord wir) {
    _distributionSet = new HashSet<Participant>();

    // if familiar task specified, get the participant(s) who completed that task,
    // & offer this item to them - no more to do
    if (_familiarParticipantTask != null) {
      Set<Participant> pSet = _rm.getWhoCompletedTask(_familiarParticipantTask, wir);
      if (pSet != null) _distributionSet.addAll(pSet);
    } else {
      // make sure each participant is added only once
      ArrayList<String> uniqueIDs = new ArrayList<String>();

      // add Participants
      for (Participant p : _participants) {
        uniqueIDs.add(p.getID());
        _distributionSet.add(p);
      }

      // add roles
      for (Role role : _roles) {
        Set<Participant> pSet = _rm.getOrgDataSet().castToParticipantSet(role.getResources());
        pSet.addAll(_rm.getOrgDataSet().getParticipantsInDescendantRoles(role));
        for (Participant p : pSet) {
          addParticipantToDistributionSet(_distributionSet, uniqueIDs, p);
        }
      }

      // add dynamic params
      for (DynParam param : _dynParams) {
        Set<Participant> pSet = param.evaluate(wir);
        for (Participant p : pSet) {
          addParticipantToDistributionSet(_distributionSet, uniqueIDs, p);
        }
      }

      // apply each filter
      for (AbstractFilter filter : _filters)
        _distributionSet = (HashSet<Participant>) filter.performFilter(_distributionSet);

      // apply each constraint
      for (AbstractConstraint constraint : _constraints)
        _distributionSet =
            (HashSet<Participant>) constraint.performConstraint(_distributionSet, wir);
    }

    // ok - got our final set
    return _distributionSet;
  }
  private void parseFilters(Element e, Namespace nsYawl) throws ResourceParseException {

    // get the Filters
    Element eFilters = e.getChild("filters", nsYawl);
    if (eFilters != null) {
      List<Element> filters = eFilters.getChildren("filter", nsYawl);
      if (filters == null)
        throw new ResourceParseException("No filter elements found in filters element");

      for (Element eFilter : filters) {
        String filterClassName = eFilter.getChildText("name", nsYawl);
        if (filterClassName != null) {
          AbstractFilter filter = PluginFactory.newFilterInstance(filterClassName);
          if (filter != null) {
            filter.setParams(parseParams(eFilter, nsYawl));
            _filters.add(filter);
          } else throw new ResourceParseException("Unknown filter name: " + filterClassName);
        } else throw new ResourceParseException("Missing filter element: name");
      }
    }
  }