package jetbrains.mps.ide.modelchecker.platform.actions;

/*Generated by MPS */

import com.intellij.openapi.components.State;
import com.intellij.openapi.components.Storage;
import jetbrains.mps.annotations.GeneratedClass;
import com.intellij.openapi.components.PersistentStateComponent;
import com.intellij.openapi.application.ApplicationManager;
import java.util.List;
import jetbrains.mps.checkers.IChecker;
import org.jetbrains.annotations.NotNull;
import jetbrains.mps.project.Project;
import jetbrains.mps.internal.collections.runtime.ListSequence;
import java.util.ArrayList;
import jetbrains.mps.errors.CheckerRegistry;
import jetbrains.mps.errors.item.IssueKindReportItem;

/**
 * A persistent state component responsible for accessing and editing "Model Checker" settings.
 * <p>
 * See {@link jetbrains.mps.checkers.IChecker }
 * See {@link jetbrains.mps.ide.modelchecker.platform.actions.ModelCheckerTool }
 * See {@link jetbrains.mps.ide.modelchecker.platform.actions.ModelCheckerViewer }
 */
@State(name = "ModelCheckerSettings", storages = @Storage(value = "modelCheckerSettings.xml")
, reportStatistic = true)
@GeneratedClass(node = "r:5754bb7d-f802-4a0f-bd3d-0764f0d71413(jetbrains.mps.ide.modelchecker.platform.actions)/3719390199793464912", model = "r:5754bb7d-f802-4a0f-bd3d-0764f0d71413(jetbrains.mps.ide.modelchecker.platform.actions)")
public class ModelCheckerSettings implements PersistentStateComponent<ModelCheckerSettings.MyState> {
  private MyState myState = new MyState();

  public ModelCheckerSettings() {
  }

  @Override
  public MyState getState() {
    return myState;
  }
  @Override
  public void loadState(MyState state) {
    myState = state;
  }

  public static ModelCheckerSettings getInstance() {
    // XXX as long as clients query specific checkers for a given project, shall become a project service, perhaps?
    return ApplicationManager.getApplication().getService(ModelCheckerSettings.class);
  }

  /**
   * Retrieves the list of all "specific" (in the sense that they are doing some job themselves) checkers 
   * currently active according to the settings. 
   * <p>
   * See {@link jetbrains.mps.errors.item.IssueKindReportItem } for the list of checker levels. 
   * Checkers registered at the level {@code KindLevel.MANUAL } are included if "additional checks" is selected.
   * <p>
   */
  public List<IChecker<?, ?>> getSpecificCheckers(@NotNull Project mpsProject) {
    List<IChecker<?, ?>> result = ListSequence.fromList(new ArrayList<IChecker<?, ?>>());
    CheckerRegistry checkerRegistry = mpsProject.getComponent(CheckerRegistry.class);
    if (checkerRegistry == null) {
      return result;
    }
    IssueKindReportItem.KindLevel checkingLevel = myState.myCheckingLevel.getKindLevel();
    for (IChecker<?, ?> checker : ListSequence.fromList(checkerRegistry.getCheckers())) {
      IssueKindReportItem.KindLevel checkerLevel = checker.getCategory().getKindLevel();
      switch (checkerLevel) {
        case MANUAL:
          if (isIncludeAdditionalChecks()) {
            ListSequence.fromList(result).addElement(checker);
          }
        default:
          if (checkerLevel.compareTo(checkingLevel) <= 0) {
            ListSequence.fromList(result).addElement(checker);
          }
      }
    }

    return result;
  }

  public CheckingLevel getCheckingLevel() {
    return myState.myCheckingLevel;
  }
  public void setCheckingLevel(CheckingLevel checkingLevel) {
    myState.myCheckingLevel = checkingLevel;
  }
  public boolean isIncludeAdditionalChecks() {
    return myState.myIncludeAdditionalChecks;
  }
  public void setIncludeAdditionalChecks(boolean checkSpecific) {
    myState.myIncludeAdditionalChecks = checkSpecific;
  }
  public boolean isCheckStubs() {
    return myState.myCheckStubs;
  }
  public void setCheckStubs(boolean checkStubs) {
    myState.myCheckStubs = checkStubs;
  }
  public boolean isCheckBeforeCommit() {
    return myState.myCheckBeforeCommit;
  }
  public void setCheckBeforeCommit(boolean checkBeforeCommit) {
    myState.myCheckBeforeCommit = checkBeforeCommit;
  }
  public boolean isRunInParallel() {
    return myState.myRunInParallel;
  }
  public void setRunInParallel(boolean runInParallel) {
    myState.myRunInParallel = runInParallel;
  }

  public static class MyState {
    public CheckingLevel myCheckingLevel = CheckingLevel.TYPESYSTEM;
    public boolean myIncludeAdditionalChecks = true;
    public boolean myCheckBeforeCommit = true;
    public boolean myCheckStubs = false;
    public boolean myRunInParallel = true;
    public MyState() {
    }
  }
  public enum CheckingLevel {
    BASIC(IssueKindReportItem.KindLevel.PROJECT, "Basic", "Project structure is correct"),
    STRUCTURE(IssueKindReportItem.KindLevel.STRUCTURE, "Structure", "Code conforms with languages' structure", "Each reference has target"),
    CONSTRAINTS(IssueKindReportItem.KindLevel.CONSTRAINTS, "Constraints", "Code satisfies languages' constraints"),
    TYPESYSTEM(IssueKindReportItem.KindLevel.TYPESYSTEM, "Typesystem", "Code passes typesystem checks");


    private IssueKindReportItem.KindLevel myKindLevel;
    private String myPresentation;
    private String[] myChecks;
    CheckingLevel(IssueKindReportItem.KindLevel kindLevel, String presentation, String... checks) {
      myKindLevel = kindLevel;
      myPresentation = presentation;
      myChecks = checks;
    }
    public IssueKindReportItem.KindLevel getKindLevel() {
      return myKindLevel;
    }
    public String getPresentation() {
      return myPresentation;
    }
    public String getLongDescription() {
      StringBuilder sb = new StringBuilder("Checks that:\n");
      for (int i = 0; i <= this.ordinal(); i++) {
        for (String s : CheckingLevel.values()[i].myChecks) {
          sb.append("-").append(s).append("\n");
        }
      }
      return sb.toString();
    }
  }
}
