@Override
  public DataSet processData(DataSet input) {

    List<Datum> temp = input.getDataOfType(DistanceMatrix.class);
    if (temp.size() != 1) {
      throw new IllegalArgumentException(
          "RemoveNaNFromDistanceMatrixPlugin: preProcessParameters: Must select one Distance Matrix");
    }

    DistanceMatrix origMatrix = (DistanceMatrix) temp.get(0).getData();
    String origName = temp.get(0).getName();

    TaxaList taxa = origMatrix.getTaxaList();
    int numTaxa = taxa.numberOfTaxa();
    BitSet[] whichNaN = new BitSet[numTaxa];

    for (int t = 0; t < numTaxa; t++) {
      whichNaN[t] = new OpenBitSet(numTaxa);
    }

    for (int x = 0; x < numTaxa; x++) {
      for (int y = x; y < numTaxa; y++) {
        if (Double.isNaN(origMatrix.getDistance(x, y))) {
          whichNaN[x].fastSet(y);
          whichNaN[y].fastSet(x);
        }
      }
    }

    List<Integer> taxaToRemove = new ArrayList<>();
    long highestCount = -1;
    while (highestCount != 0) {
      highestCount = 0;
      int highestTaxon = -1;
      for (int t = 0; t < numTaxa; t++) {
        long currentCount = whichNaN[t].cardinality();
        if (currentCount > highestCount) {
          highestCount = currentCount;
          highestTaxon = t;
        }
      }
      if (highestCount != 0) {
        taxaToRemove.add(highestTaxon);
        for (int t = 0; t < numTaxa; t++) {
          whichNaN[t].fastClear(highestTaxon);
          whichNaN[highestTaxon].fastClear(t);
        }
      }
    }

    if (!taxaToRemove.isEmpty()) {

      int newNumTaxa = numTaxa - taxaToRemove.size();
      int[] origIndex = new int[newNumTaxa];
      TaxaListBuilder builder = new TaxaListBuilder();
      int count = 0;
      for (int t = 0; t < numTaxa; t++) {
        if (!taxaToRemove.contains(t)) {
          builder.add(taxa.get(t));
          origIndex[count++] = t;
        }
      }
      TaxaList newTaxaList = builder.build();

      double[][] result = new double[newNumTaxa][newNumTaxa];
      for (int x = 0; x < newNumTaxa; x++) {
        for (int y = x; y < newNumTaxa; y++) {
          result[x][y] = result[y][x] = origMatrix.getDistance(origIndex[x], origIndex[y]);
        }
      }

      DistanceMatrix resultMatrix = new DistanceMatrix(result, newTaxaList);
      return new DataSet(new Datum(origName + " with no NaN", resultMatrix, null), this);

    } else {
      return input;
    }
  }
  public DataSet performFunction(DataSet input) {

    List data = input.getDataSet();

    int numSaveFiles = 0;
    if (mySaveFiles != null) {
      numSaveFiles = mySaveFiles.length;
    }

    if ((numSaveFiles != 0) && (numSaveFiles != 1) && (numSaveFiles != data.size())) {
      throw new IllegalStateException(
          "ExportMultiplePlugin: performFunction: number of save files should be either 0, 1 or number of input data sets.");
    }

    if ((myFileTypes != null) && (myFileTypes.length != 0)) {
      if ((myFileTypes.length != 1) && (myFileTypes.length != data.size())) {
        throw new IllegalStateException(
            "ExportMultiplePlugin: performFunction: number of files types should be either 0, 1 or number of input data sets.");
      }
    }

    for (int i = 0, n = data.size(); i < n; i++) {

      Datum datum = (Datum) data.get(i);
      DataSet current = new DataSet(datum, input.getCreator());

      if (numSaveFiles == 0) {
        myExportPlugin.setSaveFile(datum.getName());
      } else if (numSaveFiles == 1) {
        String temp;
        if (data.size() == 1) {
          temp = mySaveFiles[0];
        } else {
          temp = mySaveFiles[0].replaceFirst("\\.", (i + 1) + ".");
          if (temp.length() == mySaveFiles[0].length()) {
            temp = mySaveFiles[0] + (i + 1);
          }
        }
        myExportPlugin.setSaveFile(temp);
      } else {
        myExportPlugin.setSaveFile(mySaveFiles[i]);
      }

      if ((myFileTypes == null) || (myFileTypes.length == 0)) {
        // do nothing
      } else if (myFileTypes.length == 1) {
        myExportPlugin.setAlignmentFileType(myFileTypes[0]);
      } else {
        myExportPlugin.setAlignmentFileType(myFileTypes[i]);
      }

      DataSet filename = myExportPlugin.performFunction(current);
      myLogger.info(
          "Datum: "
              + datum.getName()
              + " Written to: "
              + filename.getDataOfType(String.class).get(0).getData());
    }

    return null;
  }