package jetbrains.mps.checkers;

/*Generated by MPS */

import jetbrains.mps.annotations.GeneratedClass;
import jetbrains.mps.logging.Logger;
import jetbrains.mps.errors.item.IssueKindReportItem;
import org.jetbrains.mps.openapi.model.SNode;
import org.jetbrains.mps.openapi.module.SRepository;
import jetbrains.mps.errors.item.FlavouredItem;
import org.jetbrains.mps.openapi.model.SNodeReference;
import jetbrains.mps.errors.item.ReportItemBase;
import jetbrains.mps.errors.item.NodeReportItemBase;
import jetbrains.mps.errors.item.RuleIdFlavouredItem;
import jetbrains.mps.errors.item.NodeReportItem;
import jetbrains.mps.errors.MessageStatus;
import jetbrains.mps.lang.smodel.generator.smodelAdapter.SNodeOperations;
import java.util.Collection;
import jetbrains.mps.errors.messageTargets.MessageTarget;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.mps.openapi.util.ProgressMonitor;
import jetbrains.mps.internal.collections.runtime.CollectionSequence;
import org.jetbrains.mps.openapi.model.SModel;
import jetbrains.mps.smodel.SModelStereotype;
import jetbrains.mps.internal.collections.runtime.Sequence;
import org.jetbrains.mps.openapi.util.Consumer;

/**
 * A special kind of checker that does nothing, but does have a {@link jetbrains.mps.checkers.ICheckingPostprocessor } to process errors
 * reported by other checkers. 
 * <p>
 * The only action this checker does in its "post processor" is to try to see whether there is an
 * instance of {@code ISuppressErrors} concept interface in the ancestor of the node that is the target of the
 * reported error. If yes, it is consulted via a call to {@code ISuppressErrors#suppress} behaviour method, and 
 * if that method returns true, the error is suppressed and a replacement (an instance of {@link jetbrains.mps.checkers.SuppressErrorsChecker.SuppressedWrapperReportItem }) is added to the list of error items. 
 * <p>
 * Only instances of {@link jetbrains.mps.errors.item.NodeReportItem } are taken into consideration.
 * <p>
 * See {@link jetbrains.mps.checkers.ErrorReportHelper }<br>
 * See {@link jetbrains.mps.errors.item.NodeReportItem }<br>
 * See {@link jetbrains.mps.checkers.CheckingSession }<br>
 */
@GeneratedClass(node = "r:ba41e9c6-15ca-4a47-95f2-6a81c2318547(jetbrains.mps.checkers)/4829978961957335527", model = "r:ba41e9c6-15ca-4a47-95f2-6a81c2318547(jetbrains.mps.checkers)")
public class SuppressErrorsChecker extends AbstractNodeCheckerInEditor {
  private static final Logger LOG = Logger.getLogger(SuppressErrorsChecker.class);
  @Override
  public IssueKindReportItem.CheckerCategory getCategory() {
    return new IssueKindReportItem.CheckerCategory(IssueKindReportItem.KindLevel.PROJECT, "suppressed error");
  }
  @Override
  protected void checkNodeInEditor(SNode node, LanguageErrorsCollector errorsCollector, SRepository repository) {
    // do nothing
  }
  public static final FlavouredItem.ReportItemFlavour<SuppressedWrapperReportItem, SNodeReference> FLAVOUR_ACTIVE_SUPPRESSOR = new ReportItemBase.SimpleReportItemFlavour<SuppressedWrapperReportItem, SNodeReference>("FLAVOUR_ACTIVE_SUPPRESSOR", SuppressedWrapperReportItem.class, (SuppressedWrapperReportItem reportItem) -> reportItem.getSuppressor());
  public class SuppressedWrapperReportItem extends NodeReportItemBase implements RuleIdFlavouredItem {
    private final NodeReportItem myOrigin;
    private final SNodeReference mySuppressor;
    public SuppressedWrapperReportItem(NodeReportItem origin, SNode suppressor) {
      super(MessageStatus.OK, origin.getNode(), "Suppressed: " + origin.getMessage());
      this.myOrigin = origin;
      this.mySuppressor = SNodeOperations.getPointer(suppressor);
    }
    public NodeReportItem getOrigin() {
      return this.myOrigin;
    }
    public SNodeReference getSuppressor() {
      return this.mySuppressor;
    }
    @Override
    public Collection<RuleIdFlavouredItem.TypesystemRuleId> getRuleId() {
      return RuleIdFlavouredItem.FLAVOUR_RULE_ID.getCollection(myOrigin);
    }
    @Override
    public MessageTarget getMessageTarget() {
      return this.myOrigin.getMessageTarget();
    }
    @Override
    public IssueKindReportItem.ItemKind getIssueKind() {
      return SuppressErrorsChecker.this.getCategory().deriveItemKind();
    }
  }
  @Nullable
  @Override
  public ICheckingPostprocessor<NodeReportItem> getPostprocessor() {
    return new ICheckingPostprocessor.AbstractCheckingPostprocessor<NodeReportItem>() {
      @Override
      public void postProcess(SRepository repository, ProgressMonitor monitor, CheckingSession<? super NodeReportItem> checkingSession) {
        ErrorReportHelper errorReportHelper = new ErrorReportHelper();
        for (Collection<? extends CheckingSession.SuppressableError<? extends IssueKindReportItem>> collection : CollectionSequence.fromCollection(checkingSession.getAllFoundErrors().values())) {
          for (CheckingSession.SuppressableError<? extends IssueKindReportItem> foundError : CollectionSequence.fromCollection(collection)) {
            IssueKindReportItem error = foundError.getError();
            if (!(error instanceof NodeReportItem)) {
              continue;
            }
            NodeReportItem nodeReportItem = (NodeReportItem) error;
            SNode node = nodeReportItem.getNode().resolve(repository);
            if (node == null) {
              if (LOG.isErrorLevel()) {
                LOG.error("node cannot be resolved in repository: " + nodeReportItem.getNode() + ", error: " + nodeReportItem.toPredicate(nodeReportItem.getIdFlavours()).serialize(), new Throwable());
              }
              continue;
            }
            SModel model = node.getModel();
            if (model == null) {
              continue;
            }
            if (SModelStereotype.isStubModel(model)) {
              continue;
            }
            SNode activeSupressor = Sequence.fromIterable(errorReportHelper.getActiveSuppressors(node, nodeReportItem)).first();
            if ((activeSupressor != null)) {
              foundError.suppress();
              NodeReportItem replacement = new SuppressedWrapperReportItem(nodeReportItem, activeSupressor);
              Consumer<? super NodeReportItem> postprocessingConsumer = checkingSession.postprocessingConsumer();
              postprocessingConsumer.consume(replacement);
            }
          }
        }
      }
    };
  }
}
