/**
   * @see org.apromore.service.ClusterService#getClusters(org.apromore.service.model.ClusterFilter)
   *     {@inheritDoc}
   */
  @Override
  public List<org.apromore.service.model.Cluster> getClusters(ClusterFilter filter) {
    MemberFragment fragment;
    ProcessAssociation pa;
    FragmentDistance distance;
    List<FragmentVersion> fs;
    List<org.apromore.service.model.Cluster> clusters = new ArrayList<>();

    List<Cluster> cinfos = cRepository.getFilteredClusters(filter);
    for (Cluster cinfo : cinfos) {
      org.apromore.service.model.Cluster c = new org.apromore.service.model.Cluster();
      c.setCluster(cinfo);

      fs = caRepository.findFragmentVersionByClusterId(cinfo.getId());
      for (FragmentVersion f : fs) {
        fragment = new MemberFragment(f.getId());
        fragment.setFragmentSize(f.getFragmentSize());
        for (ProcessModelVersion m : f.getProcessModelVersions()) {
          pa = new ProcessAssociation();
          pa.setProcessVersionId(m.getId());
          pa.setProcessVersionNumber(m.getVersionNumber());
          pa.setProcessBranchName(m.getProcessBranch().getBranchName());
          pa.setProcessId(m.getProcessBranch().getProcess().getId());
          pa.setProcessName(m.getProcessBranch().getProcess().getName());
          fragment.getProcessAssociations().add(pa);
        }

        distance =
            fdRepository.findByFragmentVersionId1AndFragmentVersionId2(
                cinfo.getMedoidId(), f.getId());
        if (distance != null) {
          fragment.setDistance(distance.getDistance());
        } else {
          fragment.setDistance(-1d);
        }
        c.addFragment(fragment);
      }
      clusters.add(c);
    }
    return clusters;
  }
  /** @see org.apromore.service.ClusterService#getPairDistances(java.util.List) {@inheritDoc} */
  @Override
  public Map<FragmentPair, Double> getPairDistances(List<Integer> fragmentIds)
      throws RepositoryException {
    FragmentDistance fragmentDistance;
    Map<FragmentPair, Double> pairDistances = new HashMap<>();
    double distance;
    Integer fid1;
    Integer fid2;
    SimpleGraph sg1;
    SimpleGraph sg2;
    SimpleGEDDeterministicGreedyCalc calc;

    for (int i = 0; i < fragmentIds.size() - 1; i++) {
      for (int j = i + 1; j < fragmentIds.size(); j++) {
        fid1 = fragmentIds.get(i);
        fid2 = fragmentIds.get(j);
        fragmentDistance = fdRepository.findByFragmentVersionId1AndFragmentVersionId2(fid1, fid2);

        if (fragmentDistance == null || fragmentDistance.getDistance() < 0) {
          try {
            sg1 = new SimpleGraphWrapper(fService.getFragment(fid1, false));
            sg2 = new SimpleGraphWrapper(fService.getFragment(fid2, false));

            calc = new SimpleGEDDeterministicGreedyCalc(1, 0.4);
            distance = calc.compute(sg1, sg2);
          } catch (LockFailedException e) {
            throw new RepositoryException(e);
          }
        } else {
          distance = fragmentDistance.getDistance();
        }

        FragmentPair pair = new FragmentPair(fid1, fid2);
        pairDistances.put(pair, distance);
      }
    }

    return pairDistances;
  }
  /** @see org.apromore.service.ClusterService#getCluster(Integer) {@inheritDoc} */
  @Override
  public org.apromore.service.model.Cluster getCluster(Integer clusterId) {
    MemberFragment fragment;
    ProcessAssociation pa;
    FragmentDistance distance;
    Cluster cinfo = cRepository.findOne(clusterId);

    org.apromore.service.model.Cluster c = new org.apromore.service.model.Cluster();
    c.setCluster(cinfo);

    List<FragmentVersion> fs = caRepository.findFragmentVersionByClusterId(clusterId);
    for (FragmentVersion f : fs) {
      fragment = new MemberFragment(f.getId());
      fragment.setFragmentSize(f.getFragmentSize());
      for (ProcessModelVersion m : f.getProcessModelVersions()) {
        pa = new ProcessAssociation();
        pa.setProcessVersionId(m.getId());
        pa.setProcessVersionNumber(m.getVersionNumber());
        pa.setProcessBranchName(m.getProcessBranch().getBranchName());
        pa.setProcessId(m.getProcessBranch().getProcess().getId());
        pa.setProcessName(m.getProcessBranch().getProcess().getName());
        fragment.getProcessAssociations().add(pa);
      }

      distance =
          fdRepository.findByFragmentVersionId1AndFragmentVersionId2(
              cinfo.getMedoidId(), f.getId());
      if (distance != null) {
        fragment.setDistance(distance.getDistance());
      } else {
        fragment.setDistance(-1d);
      }
      c.addFragment(fragment);
    }
    return c;
  }