private static Double evaluateWeight(final ITrustedCss opinionSource) {

    if (opinionSource.getDirectTrust().getValue() == null
        || opinionSource.getSimilarity() == null) {
      return null; // TODO or 0.0d???
    }

    return (opinionSource.getDirectTrust().getValue() * opinionSource.getSimilarity());
  }
  /*
   * Map<K,V> = Map<TRUSTEE_TEID,TRUSTEE>
   */
  private Map<TrustedEntityId, ITrustedCss> retrieveTopNCss(final TrustedEntityId trustorId)
      throws TrustException {

    final Map<TrustedEntityId, ITrustedCss> result = new HashMap<TrustedEntityId, ITrustedCss>();
    final Set<ITrustedCss> cssSet = super.trustRepo.retrieveCssBySimilarity(trustorId, null, null);
    for (final ITrustedCss css : cssSet) {
      result.put(css.getTrusteeId(), css);
    }

    return result;
  }
  /*
   * @see org.societies.privacytrust.trust.api.model.ITrustedService#setProvider(org.societies.privacytrust.trust.api.model.ITrustedCss)
   */
  @Override
  public void setProvider(ITrustedCss provider) {

    if (this.provider == null && provider != null) {

      if (!provider.getServices().contains(this)) provider.getServices().add(this);
    } else if (this.provider != null) {

      if (this.provider.getServices().contains(this)) this.provider.getServices().remove(this);

      if (provider != null && !provider.getServices().contains(this))
        provider.getServices().add(this);
    }

    this.provider = provider;
  }
  /*
   * @see org.societies.privacytrust.trust.api.engine.IIndirectTrustEngine#evaluate(org.societies.api.privacytrust.trust.model.TrustedEntityId, org.societies.privacytrust.trust.api.evidence.model.ITrustEvidence)
   */
  @Override
  public Set<ITrustedEntity> evaluate(
      final TrustedEntityId trustorId, final ITrustEvidence evidence) throws TrustEngineException {

    if (trustorId == null) {
      throw new NullPointerException("trustorId can't be null");
    }
    if (evidence == null) {
      throw new NullPointerException("evidence can't be null");
    }

    LOG.debug("evaluate: trustorId={}, evidence={}", trustorId, evidence);

    final Set<ITrustedEntity> resultSet = new HashSet<ITrustedEntity>();

    if (!this.areRelevant(trustorId, evidence)) {
      return resultSet;
    }

    try {
      // Does similarity between trustor and subject needs re-evaluation?
      boolean doSimilarityEval = false;
      // Create the trusted entity the evidence object refers to if not already available
      ITrustedEntity trustee =
          (ITrustedEntity) this.trustRepo.retrieveEntity(trustorId, evidence.getObjectId());
      if (trustee == null) {
        trustee = super.trustRepo.createEntity(trustorId, evidence.getObjectId());
      } else {
        doSimilarityEval = true;
      }
      LOG.debug("evaluate: doSimilarity={}", doSimilarityEval);
      resultSet.add(trustee);

      switch (evidence.getType()) {

          // Update value
        case DIRECTLY_TRUSTED:
          // Check if similarity between trustor and subject needs re-evaluation
          if (doSimilarityEval
              && TrustedEntityType.CSS == evidence.getSubjectId().getEntityType()) {
            final ITrustedCss subject =
                (ITrustedCss) super.createEntityIfAbsent(trustorId, evidence.getSubjectId());
            final Double similarity =
                this.trustSimilarityEvaluator.evaluateCosineSimilarity(
                    trustorId, evidence.getSubjectId());
            LOG.debug("evaluate: similarity={}", similarity);
            if (similarity != null && !Double.isNaN(similarity)) {
              subject.setSimilarity(similarity);
              super.trustRepo.updateEntity(subject);
            }
          }
          // Fetch top N users
          final Map<TrustedEntityId, ITrustedCss> topNCssMap = this.retrieveTopNCss(trustorId);
          LOG.debug("evaluate: topNCssMap={}", topNCssMap);
          double weightedOpinionSum = 0d;
          double weightSum = 0d;
          // Retrieve all Indirect Trust Evidence related to the object
          // referenced in the specified TrustEvidence
          final Set<ITrustEvidence> evidenceSet =
              super.trustEvidenceRepo.retrieveLatestEvidence(
                  null, evidence.getObjectId(), evidence.getType(), null);
          LOG.debug("evaluate: evidenceSet={}", evidenceSet);
          for (final ITrustEvidence relatedEvidence : evidenceSet) {
            if (!(relatedEvidence.getInfo() instanceof Double)) {
              LOG.warn("Related evidence " + relatedEvidence + " has no trust value!");
              continue;
            }
            final ITrustedCss opinionSource = topNCssMap.get(relatedEvidence.getSubjectId());
            if (opinionSource == null) {
              LOG.warn(
                  "Could not find CSS trust relationship with related evidence subject '"
                      + relatedEvidence.getSubjectId()
                      + "'");
              continue;
            }
            final Double weight = evaluateWeight(opinionSource);
            Double weightedOpinion = null;
            if (weight != null) {
              final double meanOpinion =
                  this.retrieveMeanTrustOpinion(relatedEvidence.getSubjectId());
              weightedOpinion = weight * ((Double) relatedEvidence.getInfo() - meanOpinion);
              LOG.debug(
                  "evaluate: subjectId={}, meanOpinion={}, weightedOpinion={}",
                  new Object[] {relatedEvidence.getSubjectId(), meanOpinion, weightedOpinion});
            }
            if (weightedOpinion == null) {
              LOG.warn(
                  "Ignoring related evidence " + relatedEvidence + ": Weighted opinion is null");
              continue;
            }
            weightedOpinionSum += weightedOpinion;
            weightSum += Math.abs(weight);
          }
          LOG.debug("evaluate: weightedOpinionSum={}, weightSum={}", weightedOpinionSum, weightSum);
          // t_x,i = avg(t_x) + weighted opinions
          double value =
              super.trustRepo.retrieveMeanTrustValue(trustorId, TrustValueType.DIRECT, null);
          final double confidence;
          if (weightSum > 0) {
            value += weightedOpinionSum / weightSum;
            confidence = 0.5d; // TODO constant or what?
          } else {
            confidence = 0.25d; // TODO constant or what?
          }
          LOG.debug("evaluate: value={}", value);
          if (value > 1) {
            value = 1.0d; // TODO use constant
          } else if (value < 0) {
            value = 0.0d; // TODO use constant
          }
          trustee.getIndirectTrust().setValue(value);
          trustee.getIndirectTrust().setConfidence(confidence);
          break;

        default:
          throw new TrustEngineException("Unsupported type: " + evidence.getType());
      }

      // Add related evidence to trustee
      trustee.addEvidence(evidence);

      // Persist updated TrustedEntities in the Trust Repository
      for (final ITrustedEntity entity : resultSet) {
        super.trustRepo.updateEntity(entity);
      }

    } catch (Exception e) {
      throw new TrustEngineException(
          "Could not evaluate indirect trust evidence " + evidence + ": " + e.getLocalizedMessage(),
          e);
    }

    return resultSet;
  }