package org.checkerframework.dataflow.analysis;

import java.util.IdentityHashMap;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import org.checkerframework.checker.interning.qual.FindDistinct;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.checkerframework.checker.nullness.qual.RequiresNonNull;
import org.checkerframework.dataflow.analysis.Store.FlowRule;
import org.checkerframework.dataflow.cfg.ControlFlowGraph;
import org.checkerframework.dataflow.cfg.UnderlyingAST;
import org.checkerframework.dataflow.cfg.block.Block;
import org.checkerframework.dataflow.cfg.block.ConditionalBlock;
import org.checkerframework.dataflow.cfg.block.ExceptionBlock;
import org.checkerframework.dataflow.cfg.block.RegularBlock;
import org.checkerframework.dataflow.cfg.block.SpecialBlock;
import org.checkerframework.dataflow.cfg.block.SpecialBlock.SpecialBlockType;
import org.checkerframework.dataflow.cfg.node.Node;
import org.checkerframework.dataflow.cfg.node.ReturnNode;
import org.checkerframework.javacutil.BugInCF;

/**
 * An implementation of a backward analysis to solve a org.checkerframework.dataflow problem given a
 * control flow graph and a backward transfer function.
 *
 * @param <V> the abstract value type to be tracked by the analysis
 * @param <S> the store type used in the analysis
 * @param <T> the transfer function type that is used to approximate runtime behavior
 */
public class BackwardAnalysisImpl<
        V extends AbstractValue<V>, S extends Store<S>, T extends BackwardTransferFunction<V, S>>
    extends AbstractAnalysis<V, S, T> implements BackwardAnalysis<V, S, T> {

  // TODO: Add widening support like what the forward analysis does.

  /** Out stores after every basic block (assumed to be 'no information' if not present). */
  protected final IdentityHashMap<Block, S> outStores = new IdentityHashMap<>();

  /**
   * Exception store of an exception block, propagated by exceptional successors of its exception
   * block, and merged with the normal {@link TransferResult}.
   */
  protected final IdentityHashMap<ExceptionBlock, S> exceptionStores = new IdentityHashMap<>();

  /** The store right before the entry block. */
  protected @Nullable S storeAtEntry = null;

  // `@code`, not `@link`, because dataflow module doesn't depend on framework module.
  /**
   * Construct an object that can perform a org.checkerframework.dataflow backward analysis over a
   * control flow graph. When using this constructor, the transfer function is set later by the
   * subclass, e.g., {@code org.checkerframework.framework.flow.CFAbstractAnalysis}.
   */
  public BackwardAnalysisImpl() {
    super(Direction.BACKWARD);
  }

  /**
   * Construct an object that can perform a org.checkerframework.dataflow backward analysis over a
   * control flow graph given a transfer function.
   *
   * @param transferFunction the transfer function
   */
  public BackwardAnalysisImpl(@Nullable T transferFunction) {
    this();
    this.transferFunction = transferFunction;
  }

  @Override
  public void performAnalysis(ControlFlowGraph cfg) {
    if (isRunning) {
      throw new BugInCF("performAnalysis() shouldn't be called when the analysis is running.");
    }
    isRunning = true;
    try {
      init(cfg);
      while (!worklist.isEmpty()) {
        Block b = worklist.poll();
        performAnalysisBlock(b);
      }
    } finally {
      assert isRunning;
      // In case performAnalysisBlock crashed, reset isRunning to false.
      isRunning = false;
    }
  }

  @Override
  public void performAnalysisBlock(Block b) {
    switch (b.getType()) {
      case REGULAR_BLOCK:
        {
          RegularBlock rb = (RegularBlock) b;
          TransferInput<V, S> inputAfter = getInput(rb);
          assert inputAfter != null : "@AssumeAssertion(nullness): invariant";
          currentInput = inputAfter.copy();
          Node firstNode = null;
          boolean addToWorklistAgain = false;
          List<Node> nodeList = rb.getNodes();
          ListIterator<Node> reverseIter = nodeList.listIterator(nodeList.size());
          while (reverseIter.hasPrevious()) {
            Node node = reverseIter.previous();
            assert currentInput != null : "@AssumeAssertion(nullness): invariant";
            TransferResult<V, S> transferResult = callTransferFunction(node, currentInput);
            addToWorklistAgain |= updateNodeValues(node, transferResult);
            currentInput = new TransferInput<>(node, this, transferResult);
            firstNode = node;
          }
          // Propagate store to predecessors
          for (Block pred : rb.getPredecessors()) {
            assert currentInput != null : "@AssumeAssertion(nullness): invariant";
            propagateStoresTo(
                pred, firstNode, currentInput, FlowRule.EACH_TO_EACH, addToWorklistAgain);
          }
          break;
        }
      case EXCEPTION_BLOCK:
        {
          ExceptionBlock eb = (ExceptionBlock) b;
          TransferInput<V, S> inputAfter = getInput(eb);
          assert inputAfter != null : "@AssumeAssertion(nullness): invariant";
          currentInput = inputAfter.copy();
          Node node = eb.getNode();
          TransferResult<V, S> transferResult = callTransferFunction(node, currentInput);
          boolean addToWorklistAgain = updateNodeValues(node, transferResult);
          // Merge transferResult with exceptionStore if there exists one
          S exceptionStore = exceptionStores.get(eb);
          S mergedStore =
              exceptionStore != null
                  ? transferResult.getRegularStore().leastUpperBound(exceptionStore)
                  : transferResult.getRegularStore();
          for (Block pred : eb.getPredecessors()) {
            addStoreAfter(pred, node, mergedStore, addToWorklistAgain);
          }
          break;
        }
      case CONDITIONAL_BLOCK:
        {
          ConditionalBlock cb = (ConditionalBlock) b;
          TransferInput<V, S> inputAfter = getInput(cb);
          assert inputAfter != null : "@AssumeAssertion(nullness): invariant";
          TransferInput<V, S> input = inputAfter.copy();
          for (Block pred : cb.getPredecessors()) {
            propagateStoresTo(pred, null, input, FlowRule.EACH_TO_EACH, false);
          }
          break;
        }
      case SPECIAL_BLOCK:
        {
          // Special basic blocks are empty and cannot throw exceptions,
          // thus there is no need to perform any analysis.
          SpecialBlock sb = (SpecialBlock) b;
          final SpecialBlockType sType = sb.getSpecialType();
          if (sType == SpecialBlockType.ENTRY) {
            // storage the store at entry
            storeAtEntry = outStores.get(sb);
          } else {
            assert sType == SpecialBlockType.EXIT || sType == SpecialBlockType.EXCEPTIONAL_EXIT;
            TransferInput<V, S> input = getInput(sb);
            assert input != null : "@AssumeAssertion(nullness): invariant";
            for (Block pred : sb.getPredecessors()) {
              propagateStoresTo(pred, null, input, FlowRule.EACH_TO_EACH, false);
            }
          }
          break;
        }
      default:
        throw new BugInCF("Unexpected block type: " + b.getType());
    }
  }

  @Override
  public @Nullable TransferInput<V, S> getInput(Block b) {
    return inputs.get(b);
  }

  @Override
  public @Nullable S getEntryStore() {
    return storeAtEntry;
  }

  @Override
  protected void initFields(ControlFlowGraph cfg) {
    super.initFields(cfg);
    outStores.clear();
    exceptionStores.clear();
    // storeAtEntry is null before analysis begin
    storeAtEntry = null;
  }

  @Override
  @RequiresNonNull("cfg")
  protected void initInitialInputs() {
    worklist.process(cfg);
    SpecialBlock regularExitBlock = cfg.getRegularExitBlock();
    SpecialBlock exceptionExitBlock = cfg.getExceptionalExitBlock();
    if (worklist.depthFirstOrder.get(regularExitBlock) == null
        && worklist.depthFirstOrder.get(exceptionExitBlock) == null) {
      throw new BugInCF(
          "regularExitBlock and exceptionExitBlock should never both be null at the same time.");
    }
    UnderlyingAST underlyingAST = cfg.getUnderlyingAST();
    List<ReturnNode> returnNodes = cfg.getReturnNodes();
    assert transferFunction != null : "@AssumeAssertion(nullness): invariant";
    S normalInitialStore = transferFunction.initialNormalExitStore(underlyingAST, returnNodes);
    S exceptionalInitialStore = transferFunction.initialExceptionalExitStore(underlyingAST);
    // If regularExitBlock or exceptionExitBlock is reachable in the control flow graph, then
    // initialize it as a start point of the analysis.
    if (worklist.depthFirstOrder.get(regularExitBlock) != null) {
      worklist.add(regularExitBlock);
      inputs.put(regularExitBlock, new TransferInput<>(null, this, normalInitialStore));
      outStores.put(regularExitBlock, normalInitialStore);
    }
    if (worklist.depthFirstOrder.get(exceptionExitBlock) != null) {
      worklist.add(exceptionExitBlock);
      inputs.put(exceptionExitBlock, new TransferInput<>(null, this, exceptionalInitialStore));
      outStores.put(exceptionExitBlock, exceptionalInitialStore);
    }
    if (worklist.isEmpty()) {
      throw new BugInCF("The worklist needs at least one exit block as starting point.");
    }
    if (inputs.isEmpty() || outStores.isEmpty()) {
      throw new BugInCF("At least one input and one output store are required.");
    }
  }

  @Override
  protected void propagateStoresTo(
      Block pred,
      @Nullable Node node,
      TransferInput<V, S> currentInput,
      FlowRule flowRule,
      boolean addToWorklistAgain) {
    if (flowRule != FlowRule.EACH_TO_EACH) {
      throw new BugInCF(
          "Backward analysis always propagates EACH to EACH, because there is no control flow.");
    }

    addStoreAfter(pred, node, currentInput.getRegularStore(), addToWorklistAgain);
  }

  /**
   * Add a store after the basic block {@code pred} by merging with the existing stores for that
   * location.
   *
   * @param pred the basic block
   * @param node the node of the basic block {@code b}
   * @param s the store being added
   * @param addBlockToWorklist whether the basic block {@code b} should be added back to {@code
   *     Worklist}
   */
  protected void addStoreAfter(Block pred, @Nullable Node node, S s, boolean addBlockToWorklist) {
    // If the block pred is an exception block, decide whether the block of passing node is an
    // exceptional successor of the block pred
    if (pred instanceof ExceptionBlock
        && ((ExceptionBlock) pred).getSuccessor() != null
        && node != null) {
      @Nullable Block succBlock = ((ExceptionBlock) pred).getSuccessor();
      @Nullable Block block = node.getBlock();
      if (succBlock != null && block != null && succBlock.getUid() == block.getUid()) {
        // If the block of passing node is an exceptional successor of Block pred, propagate
        // store to the exceptionStores. Currently it doesn't track the label of an
        // exceptional edge from exception block to its exceptional successors in backward
        // direction. Instead, all exception stores of exceptional successors of an
        // exception block will merge to one exception store at the exception block
        ExceptionBlock ebPred = (ExceptionBlock) pred;
        S exceptionStore = exceptionStores.get(ebPred);
        S newExceptionStore = (exceptionStore != null) ? exceptionStore.leastUpperBound(s) : s;
        if (!newExceptionStore.equals(exceptionStore)) {
          exceptionStores.put(ebPred, newExceptionStore);
          inputs.put(ebPred, new TransferInput<V, S>(node, this, newExceptionStore));
          addBlockToWorklist = true;
        }
      }
    } else {
      S predOutStore = getStoreAfter(pred);
      S newPredOutStore = (predOutStore != null) ? predOutStore.leastUpperBound(s) : s;
      if (!newPredOutStore.equals(predOutStore)) {
        outStores.put(pred, newPredOutStore);
        inputs.put(pred, new TransferInput<>(node, this, newPredOutStore));
        addBlockToWorklist = true;
      }
    }
    if (addBlockToWorklist) {
      addToWorklist(pred);
    }
  }

  /**
   * Returns the store corresponding to the location right after the basic block {@code b}.
   *
   * @param b the given block
   * @return the store right after the given block
   */
  protected @Nullable S getStoreAfter(Block b) {
    return readFromStore(outStores, b);
  }

  @Override
  public S runAnalysisFor(
      @FindDistinct Node node,
      Analysis.BeforeOrAfter preOrPost,
      TransferInput<V, S> blockTransferInput,
      IdentityHashMap<Node, V> nodeValues,
      Map<TransferInput<V, S>, IdentityHashMap<Node, TransferResult<V, S>>> analysisCaches) {
    Block block = node.getBlock();
    assert block != null : "@AssumeAssertion(nullness): invariant";
    Node oldCurrentNode = currentNode;
    if (isRunning) {
      assert currentInput != null : "@AssumeAssertion(nullness): invariant";
      return currentInput.getRegularStore();
    }
    isRunning = true;
    try {
      switch (block.getType()) {
        case REGULAR_BLOCK:
          {
            RegularBlock rBlock = (RegularBlock) block;
            // Apply transfer function to contents until we found the node we are looking for.
            TransferInput<V, S> store = blockTransferInput;
            List<Node> nodeList = rBlock.getNodes();
            ListIterator<Node> reverseIter = nodeList.listIterator(nodeList.size());
            while (reverseIter.hasPrevious()) {
              Node n = reverseIter.previous();
              setCurrentNode(n);
              if (n == node && preOrPost == Analysis.BeforeOrAfter.AFTER) {
                return store.getRegularStore();
              }
              // Copy the store to avoid changing other blocks' transfer inputs in
              // {@link #inputs}
              TransferResult<V, S> transferResult = callTransferFunction(n, store.copy());
              if (n == node) {
                return transferResult.getRegularStore();
              }
              store = new TransferInput<>(n, this, transferResult);
            }
            throw new BugInCF("node %s is not in node.getBlock()=%s", node, block);
          }
        case EXCEPTION_BLOCK:
          {
            ExceptionBlock eb = (ExceptionBlock) block;
            if (eb.getNode() != node) {
              throw new BugInCF(
                  "Node should be equal to eb.getNode(). But get: node: "
                      + node
                      + "\teb.getNode(): "
                      + eb.getNode());
            }
            if (preOrPost == Analysis.BeforeOrAfter.AFTER) {
              return blockTransferInput.getRegularStore();
            }
            setCurrentNode(node);
            // Copy the store to avoid changing other blocks' transfer inputs in {@link #inputs}
            TransferResult<V, S> transferResult =
                callTransferFunction(node, blockTransferInput.copy());
            // Merge transfer result with the exception store of this exceptional block
            S exceptionStore = exceptionStores.get(eb);
            return exceptionStore == null
                ? transferResult.getRegularStore()
                : transferResult.getRegularStore().leastUpperBound(exceptionStore);
          }
        default:
          // Only regular blocks and exceptional blocks can hold nodes.
          throw new BugInCF("Unexpected block type: " + block.getType());
      }

    } finally {
      setCurrentNode(oldCurrentNode);
      isRunning = false;
    }
  }
}
