/*
   * for internal usage, creates a NOTIFY notify, asks the content to the
   * concrete implementation component, and then sends the request to the
   * subscriber
   */
  public void createAndSendNotify(
      EntityManager entityManager,
      Subscription subscription,
      Dialog dialog,
      ImplementedSubscriptionControlSbbLocalObject childSbb)
      throws TransactionDoesNotExistException, SipException, ParseException {

    // create notify
    Request notify = createNotify(dialog, subscription);
    // add content if subscription is active
    if (subscription.getStatus().equals(Subscription.Status.active)) {
      if (subscription.getKey().getEventPackage().endsWith(".winfo")) {
        // winfo content, increment version before adding the content
        subscription.incrementVersion();
        entityManager.persist(subscription);
        entityManager.flush();
        notify.setContent(
            sipSubscriptionHandler
                .sbb
                .getWInfoSubscriptionHandler()
                .getFullWatcherInfoContent(entityManager, subscription),
            sipSubscriptionHandler.sbb.getWInfoSubscriptionHandler().getWatcherInfoContentHeader());
      } else {
        // specific event package content
        NotifyContent notifyContent = childSbb.getNotifyContent(subscription);
        // add content
        if (notifyContent != null) {
          try {
            notify =
                setNotifyContent(
                    subscription,
                    notify,
                    notifyContent.getContent(),
                    notifyContent.getContentTypeHeader(),
                    childSbb);
          } catch (Exception e) {
            logger.error("failed to set notify content", e);
          }
        }
      }
    }

    // ....aayush added code here (with ref issue #567)
    notify.addHeader(addPChargingVectorHeader());

    // send notify
    ClientTransaction clientTransaction =
        sipSubscriptionHandler.sbb.getSipProvider().getNewClientTransaction(notify);
    dialog.sendRequest(clientTransaction);
    if (logger.isDebugEnabled()) {
      logger.debug("Request sent:\n" + notify.toString());
    }
  }
  public void notifySipSubscriber(
      Object content,
      ContentTypeHeader contentTypeHeader,
      Subscription subscription,
      EntityManager entityManager,
      ImplementedSubscriptionControlSbbLocalObject childSbb) {

    try {
      // get subscription dialog
      ActivityContextInterface dialogACI =
          sipSubscriptionHandler
              .sbb
              .getActivityContextNamingfacility()
              .lookup(subscription.getKey().toString());
      if (dialogACI != null) {
        Dialog dialog = (Dialog) dialogACI.getActivity();
        // create notify
        Request notify = createNotify(dialog, subscription);
        // add content
        if (content != null) {
          notify = setNotifyContent(subscription, notify, content, contentTypeHeader, childSbb);
        }

        // ....aayush added code here (with ref issue #567)
        notify.addHeader(addPChargingVectorHeader());

        // send notify in dialog related with subscription
        dialog.sendRequest(
            sipSubscriptionHandler.sbb.getSipProvider().getNewClientTransaction(notify));
        if (logger.isDebugEnabled()) {
          logger.debug(
              "NotifySubscribers: subscription "
                  + subscription.getKey()
                  + " sent request:\n"
                  + notify.toString());
        }
      } else {
        // clean up
        logger.warn(
            "Unable to find dialog aci to notify subscription "
                + subscription.getKey()
                + ". Removing subscription data");
        sipSubscriptionHandler.sbb.removeSubscriptionData(
            entityManager, subscription, null, null, childSbb);
      }

    } catch (Exception e) {
      logger.error("failed to notify subscriber", e);
    }
  }
  public void removingSubscription(
      Subscription subscription, String presRulesAUID, String presRulesDocumentName) {

    if (logger.isDebugEnabled()) {
      logger.debug("removingSubscription(" + subscription + ")");
    }
    // get combined rules cmp
    Map combinedRules = sbb.getCombinedRules();
    if (combinedRules != null) {
      // remove subscription from map
      if (logger.isDebugEnabled()) {
        logger.debug("combined rules: " + combinedRules.keySet());
      }
      PresRuleCMPKey cmpKey =
          new PresRuleCMPKey(
              subscription.getSubscriber(),
              subscription.getNotifier(),
              subscription.getKey().getEventPackage(),
              subscription.getKey().getRealEventId());
      if (combinedRules.remove(cmpKey) != null) {
        if (logger.isDebugEnabled()) {
          logger.debug("removed rule from combined rules map (" + subscription + ")");
        }
        // check if subscription to pres-rules still needed
        boolean subscriptionNeeded = false;
        for (Object k : combinedRules.keySet()) {
          PresRuleCMPKey presRuleCMPKey = (PresRuleCMPKey) k;
          if (presRuleCMPKey.getNotifierWithoutParams().equals(cmpKey.getNotifierWithoutParams())
              && presRuleCMPKey.getEventPackage().equals(subscription.getKey().getEventPackage())) {
            if (logger.isDebugEnabled()) {
              logger.debug("subscription needed due to rule " + presRuleCMPKey);
            }
            subscriptionNeeded = true;
            break;
          }
        }
        if (!subscriptionNeeded) {
          if (logger.isDebugEnabled()) {
            logger.debug("subscription not needed");
          }
          DocumentSelector documentSelector =
              getDocumentSelector(
                  cmpKey.getNotifierWithoutParams(), presRulesAUID, presRulesDocumentName);
          sbb.getXDMClientControlSbb().unsubscribeDocument(documentSelector);
        }
      }
    }
  }
  public NotifyContent getNotifyContent(Subscription subscription) {
    try {

      ComposedPublication composedPublication =
          sbb.getPublicationChildSbb()
              .getComposedPublication(
                  subscription.getNotifier(), subscription.getKey().getEventPackage());
      if (composedPublication != null) {
        return new NotifyContent(
            composedPublication.getUnmarshalledContent(),
            sbb.getHeaderFactory()
                .createContentTypeHeader(
                    composedPublication.getContentType(), composedPublication.getContentSubType()));
      }
    } catch (Exception e) {
      logger.error("failed to get notify content", e);
    }
    return null;
  }
  public Request setNotifyContent(
      Subscription subscription,
      Request notify,
      Object content,
      ContentTypeHeader contentTypeHeader,
      ImplementedSubscriptionControlSbbLocalObject childSbb)
      throws JAXBException, ParseException, IOException {

    if (!subscription.getResourceList()) {
      // filter content per subscriber (notifier rules)
      Object filteredContent =
          childSbb.filterContentPerSubscriber(
              subscription.getSubscriber(),
              subscription.getNotifier(),
              subscription.getKey().getEventPackage(),
              content);
      // filter content per notifier (subscriber rules)
      // TODO
      // marshall content to string
      StringWriter stringWriter = new StringWriter();
      childSbb.getMarshaller().marshal(filteredContent, stringWriter);
      notify.setContent(stringWriter.toString(), contentTypeHeader);
      stringWriter.close();
    } else {
      // resource list subscription, no filtering
      if (content instanceof JAXBElement) {
        // marshall content to string
        StringWriter stringWriter = new StringWriter();
        childSbb.getMarshaller().marshal(content, stringWriter);
        notify.setContent(stringWriter.toString(), contentTypeHeader);
        stringWriter.close();
      } else {
        notify.setContent(content, contentTypeHeader);
      }
    }
    return notify;
  }
  // creates a notify request and fills headers
  public Request createNotify(Dialog dialog, Subscription subscription) {

    Request notify = null;
    try {
      notify = dialog.createRequest(Request.NOTIFY);
      // add event header
      EventHeader eventHeader =
          sipSubscriptionHandler
              .sbb
              .getHeaderFactory()
              .createEventHeader(subscription.getKey().getEventPackage());
      if (subscription.getKey().getRealEventId() != null)
        eventHeader.setEventId(subscription.getKey().getRealEventId());
      notify.setHeader(eventHeader);
      // add max forwards header
      notify.setHeader(
          sipSubscriptionHandler
              .sbb
              .getHeaderFactory()
              .createMaxForwardsHeader(
                  sipSubscriptionHandler.sbb.getConfiguration().getMaxForwards()));
      /*
       * NOTIFY requests MUST contain a "Subscription-State" header with a
       * value of "active", "pending", or "terminated". The "active" value
       * indicates that the subscription has been accepted and has been
       * authorized (in most cases; see section 5.2.). The "pending" value
       * indicates that the subscription has been received, but that
       * policy information is insufficient to accept or deny the
       * subscription at this time. The "terminated" value indicates that
       * the subscription is not active.
       */
      SubscriptionStateHeader ssh = null;
      if (subscription.getStatus().equals(Subscription.Status.active)
          || subscription.getStatus().equals(Subscription.Status.pending)) {
        ssh =
            sipSubscriptionHandler
                .sbb
                .getHeaderFactory()
                .createSubscriptionStateHeader(subscription.getStatus().toString());
        /*
         * If the value of the "Subscription-State" header is "active"
         * or "pending", the notifier SHOULD also include in the
         * "Subscription- State" header an "expires" parameter which
         * indicates the time remaining on the subscription.
         */
        ssh.setExpires(subscription.getRemainingExpires());
      } else if (subscription.getStatus().equals(Subscription.Status.waiting)
          || subscription.getStatus().equals(Subscription.Status.terminated)) {
        ssh =
            sipSubscriptionHandler
                .sbb
                .getHeaderFactory()
                .createSubscriptionStateHeader("terminated");
        /*
         * If the value of the "Subscription-State" header is
         * "terminated", the notifier SHOULD also include a "reason"
         * parameter.
         */
        if (subscription.getLastEvent() != null) {
          ssh.setReasonCode(subscription.getLastEvent().toString());
        }
      }
      notify.addHeader(ssh);

      // if it's a RLS notify a required header must be present
      if (subscription.getResourceList()) {
        notify.addHeader(
            sipSubscriptionHandler.sbb.getHeaderFactory().createRequireHeader("eventlist"));
      }

    } catch (Exception e) {
      logger.error("unable to fill notify headers", e);
    }
    return notify;
  }