/*
 *  Copyright 2006-2020 The MZmine Development Team
 *
 *  This file is part of MZmine.
 *
 *  MZmine is free software; you can redistribute it and/or modify it under the terms of the GNU
 *  General Public License as published by the Free Software Foundation; either version 2 of the
 *  License, or (at your option) any later version.
 *
 *  MZmine is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
 *  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
 *  Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License along with MZmine; if not,
 *  write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
 *  USA
 */

package io.github.mzmine.modules.dataprocessing.id_ccscalc;

import com.google.common.collect.RangeMap;
import io.github.mzmine.datamodel.MZmineProject;
import io.github.mzmine.datamodel.MobilityType;
import io.github.mzmine.datamodel.RawDataFile;
import io.github.mzmine.datamodel.features.FeatureListRow;
import io.github.mzmine.datamodel.features.ModularFeature;
import io.github.mzmine.datamodel.features.ModularFeatureList;
import io.github.mzmine.parameters.ParameterSet;
import io.github.mzmine.taskcontrol.AbstractTask;
import io.github.mzmine.taskcontrol.TaskStatus;
import java.util.logging.Logger;
import javafx.collections.ObservableList;

/**
 * @author https://github.com/SteffenHeu
 * @see CCSCalcModule
 */
public class CCSCalcTask extends AbstractTask {

  private static Logger logger = Logger.getLogger(CCSCalcTask.class.getName());

  private final boolean assumeChargeState;
  private final RangeMap<Double, Integer> rangeChargeMap;
  private final ModularFeatureList[] featureLists;
  private final boolean createNewFeatureList;
  private final MZmineProject project;
  private String description;
  private double percentage;
  private int totalRows;
  private int processedRows;
  private int annotatedFeatures;

  public CCSCalcTask(MZmineProject project, ParameterSet parameters) {
    this.assumeChargeState = parameters.getParameter(CCSCalcParameters.assumeChargeStage)
        .getValue();
    this.rangeChargeMap = parameters.getParameter(CCSCalcParameters.assumeChargeStage)
        .getEmbeddedParameter()
        .getValue();
    this.featureLists = parameters.getParameter(CCSCalcParameters.featureLists).getValue()
        .getMatchingFeatureLists();
    this.createNewFeatureList = parameters.getParameter(CCSCalcParameters.createNewFeatureList)
        .getValue();
    this.project = project;

    for (ModularFeatureList featureList : featureLists) {
      totalRows += featureList.getNumberOfRows();
    }
    processedRows = 0;
    annotatedFeatures = 0;
  }

  @Override
  public String getTaskDescription() {
    return "Calculating CCS values.";
  }

  @Override
  public double getFinishedPercentage() {
    return percentage;
  }

  @Override
  public void run() {
    setStatus(TaskStatus.PROCESSING);

    ModularFeatureList workingFeatureList = null;
    for (ModularFeatureList featureList : featureLists) {
      if (createNewFeatureList) {
        workingFeatureList = featureList.createCopy(featureList.getName() + " CCS");
      } else {
        workingFeatureList = featureList;
      }

      for (FeatureListRow row : workingFeatureList.getRows()) {
        ObservableList<RawDataFile> rawDataFiles = row.getRawDataFiles();
        for (RawDataFile file : rawDataFiles) {

          ModularFeature feature = (ModularFeature) row.getFeature(file);
          if (feature == null) {
            continue;
          }

          Float mobility = feature.getMobility();
          MobilityType mobilityType = feature.getMobilityUnit();
          double mz = feature.getMZ();
          if (mobility == null || mobilityType == null) {
            continue;
          }

          int charge = feature.getCharge();
          if (charge == 0 && !assumeChargeState) {
            continue;
          } else if (charge == 0 && assumeChargeState) {
            Integer fallbackCharge = rangeChargeMap.get(mz);
            if (fallbackCharge == null) {
              continue;
            }
            charge = fallbackCharge;
          }

          Float ccs = CCSUtils.calcCCS(mz, mobility, mobilityType, charge);
          if (ccs != null) {
            feature.setCCS(ccs);
            annotatedFeatures++;
          }
        }

        processedRows++;
        percentage = totalRows / (double) processedRows;
      }

      if (workingFeatureList != featureList) {
        project.addFeatureList(workingFeatureList);
      }
    }

    logger.info("Annotated " + annotatedFeatures + " features with CCS values.");
    setStatus(TaskStatus.FINISHED);
  }
}

@@ -1217,16 +1217,91 @@
 reList;%0A
+import io.github.mzmine.datamodel.features.SimpleFeatureListAppliedMethod;%0A
 import i
@@ -1341,16 +1341,16 @@
 terSet;%0A
-
 import i
@@ -1953,16 +1953,51 @@
 roject;%0A
+  private ParameterSet parameters;%0A
   privat
@@ -2693,32 +2693,32 @@
    .getValue();%0A
-
     this.project
@@ -2728,16 +2728,50 @@
 project;
+%0A    this.parameters = parameters;
 %0A%0A    fo
@@ -4602,32 +4602,88 @@
    %7D%0A        %7D%0A%0A
+        if (isCanceled()) %7B%0A          return;%0A        %7D%0A
         processe
@@ -4753,24 +4753,152 @@
 s;%0A      %7D%0A%0A
+      workingFeatureList.getAppliedMethods()%0A          .add(new SimpleFeatureListAppliedMethod(%22CSS calculation%22, parameters));%0A
       if (wo

add applied method