/**
   * computes matrices for all actions which show whether two pattern nodes are allowed to be
   * identified by the matcher
   */
  protected void collectPotHomInfo() {

    // tells whether two pattern nodes of a given action are pot hom or not
    // e.g. : potHomMatrices[act_id][node_1][node_2]
    // protected int potHomMatrices[][][];
    potHomNodeMatrices = new int[n_graph_actions][max_n_pattern_nodes][max_n_pattern_nodes];

    for (int i = 0; i < n_graph_actions; i++)
      for (int j = 0; j < max_n_pattern_nodes; j++)
        for (int k = 0; k < max_n_pattern_nodes; k++) potHomNodeMatrices[i][j][k] = 0;

    // got through that m,atrices and set cells to '1' if two nodes
    // are potentialy homomorphic
    for (Rule action : actionRuleMap.keySet()) {
      PatternGraph pattern = action.getPattern();
      for (Node node_1 : pattern.getNodes()) {
        Collection<Node> hom_of_node_1 = new HashSet<Node>();
        hom_of_node_1 = pattern.getHomomorphic(node_1);

        for (Node node_2 : pattern.getNodes()) {
          // check whether these to nodes are potentially homomorphic
          // the pattern graph of the currrent action
          if (hom_of_node_1.contains(node_2)) {
            int act_id = actionRuleMap.get(action).intValue();
            int node_1_num = pattern_node_num.get(act_id).get(node_1).intValue();
            int node_2_num = pattern_node_num.get(act_id).get(node_2).intValue();
            potHomNodeMatrices[act_id][node_1_num][node_2_num] = 1;
          }
        }
      }
    }
  }
  /** Method coolectPatternNodesToBeKeptInfo */
  private void collectPatternNodesToBeKeptInfo() {
    patternNodeIsToBeKept = new int[n_graph_actions][max_n_pattern_nodes];

    // init the arrays with -1
    for (int i = 0; i < n_graph_actions; i++)
      for (int j = 0; j < max_n_pattern_nodes; j++) patternNodeIsToBeKept[i][j] = -1;

    // for all nodes to be kept set the corresponding array entry to the
    // appropriate replacement node number
    for (Rule action : actionRuleMap.keySet()) {
      int act_id = actionRuleMap.get(action).intValue();

      // compute the set of pattern nodes to be kept for this action
      Collection<Node> pattern_nodes_to_keep = new HashSet<Node>();
      pattern_nodes_to_keep.addAll(action.getPattern().getNodes());
      if (action.getRight() != null) {
        Graph replacement = action.getRight();
        pattern_nodes_to_keep.retainAll(replacement.getNodes());
        // iterate over the pattern nodes to be kept and store their
        // corresponding replacement node number
        for (Node node : pattern_nodes_to_keep) {
          int node_num = pattern_node_num.get(act_id).get(node).intValue();
          patternNodeIsToBeKept[act_id][node_num] =
              replacement_node_num.get(act_id).get(node).intValue();
        }
      }
    }
  }
  /** Method collectReplacementNodeIsPreservedNodeInfo */
  private void collectReplacementNodeIsPreservedNodeInfo() {
    replacementNodeIsPreservedNode = new int[n_graph_actions][max_n_replacement_nodes];

    // init the array with -1
    for (int i = 0; i < n_graph_actions; i++)
      for (int j = 0; j < max_n_replacement_nodes; j++) replacementNodeIsPreservedNode[i][j] = -1;

    // for all nodes preserved set the corresponding array entry to the
    // appropriate pattern node number
    for (Rule action : actionRuleMap.keySet()) {
      int act_id = actionRuleMap.get(action).intValue();

      if (action.getRight() != null) {
        // compute the set of replacement nodes preserved by this action
        Collection<Node> replacement_nodes_preserved = new HashSet<Node>();
        replacement_nodes_preserved.addAll(action.getRight().getNodes());
        replacement_nodes_preserved.retainAll(action.getPattern().getNodes());

        // for all those preserved replacement nodes store the
        // corresponding pattern node
        for (Node node : replacement_nodes_preserved) {
          int node_num = replacement_node_num.get(act_id).get(node).intValue();
          replacementNodeIsPreservedNode[act_id][node_num] =
              pattern_node_num.get(act_id).get(node).intValue();
        }
      }
    }
  }
  /** Method collectReplacementNodeChangesTypeToInfo */
  private void collectReplacementNodeChangesTypeToInfo() {
    replacementNodeChangesTypeTo = new int[n_graph_actions][max_n_replacement_nodes];

    // init the array with -1
    for (int i = 0; i < n_graph_actions; i++)
      for (int j = 0; j < max_n_replacement_nodes; j++) replacementNodeChangesTypeTo[i][j] = -1;

    // for all nodes preserved set the corresponding array entry to the
    // appropriate node type id
    for (Rule action : actionRuleMap.keySet()) {
      int act_id = actionRuleMap.get(action).intValue();

      if (action.getRight() != null) {
        for (Node node : action.getRight().getNodes()) {
          if (!node.changesType(action.getRight())) continue;

          int node_num = replacement_node_num.get(act_id).get(node).intValue();

          NodeType old_type = node.getNodeType();
          NodeType new_type = node.getRetypedNode(action.getRight()).getNodeType();

          if (!nodeTypeMap.get(old_type).equals(nodeTypeMap.get(new_type)))
            replacementNodeChangesTypeTo[act_id][node_num] = nodeTypeMap.get(new_type).intValue();
        }
      }
    }
  }
  /** Method collectNewInsertEdgesInfo */
  private void collectNewInsertEdgesInfo() {
    // Collection[] new_edges_of_action;
    newEdgesOfAction = new Vector<Collection<Edge>>(n_graph_actions);

    // init the array with empty HashSets
    for (int i = 0; i < n_graph_actions; i++) newEdgesOfAction.set(i, new HashSet<Edge>());

    // for all actions collect the edges to be newly inserted
    for (Rule action : actionRuleMap.keySet()) {
      int act_id = actionRuleMap.get(action).intValue();

      if (action.getRight() != null) {
        Graph replacement = action.getRight();
        // compute the set of newly inserted edges
        newEdgesOfAction.get(act_id).addAll(replacement.getEdges());
        newEdgesOfAction.get(act_id).removeAll(action.getPattern().getEdges());
      }
    }
  }
  /*
   * collect some information needed for code gen process of the data
   * structures representing the graph actions
   *
   */
  protected void collectActionInfo() {
    /* get the overall number of graph actions */
    n_graph_actions = actionRuleMap.keySet().size();

    /* get the overall maximum numbers of nodes and edges of all pattern
    and replacement graphs respectively */
    max_n_pattern_nodes = 0;
    max_n_pattern_edges = 0;
    max_n_replacement_nodes = 0;
    max_n_replacement_edges = 0;

    for (Rule act : actionRuleMap.keySet()) {
      // check whether its graphs node and edge set sizes are greater
      int size;

      size = act.getPattern().getNodes().size();
      if (size > max_n_pattern_nodes) max_n_pattern_nodes = size;
      size = act.getPattern().getEdges().size();
      if (size > max_n_pattern_edges) max_n_pattern_edges = size;

      if (act.getRight() != null) {
        size = act.getRight().getNodes().size();
        if (size > max_n_replacement_nodes) max_n_replacement_nodes = size;
        size = act.getRight().getEdges().size();
        if (size > max_n_replacement_edges) max_n_replacement_edges = size;
      }
    }

    /* compute the numbers of nodes/edges of all pattern/replacement-graphs */
    pattern_node_num = new Vector<Map<Node, Integer>>(n_graph_actions);
    pattern_edge_num = new Vector<Map<Edge, Integer>>(n_graph_actions);
    replacement_node_num = new Vector<Map<Node, Integer>>(n_graph_actions);
    replacement_edge_num = new Vector<Map<Edge, Integer>>(n_graph_actions);
    for (Rule act : actionRuleMap.keySet()) {
      int act_id = actionRuleMap.get(act).intValue();
      assert act_id < n_graph_actions
          : "action id found which was greater than the number of graph actions";

      // compute node/edge numbers
      pattern_node_num.set(act_id, new HashMap<Node, Integer>());
      pattern_edge_num.set(act_id, new HashMap<Edge, Integer>());

      // fill the map with pairs (node, node_num)
      int node_num = 0;

      for (Node node : act.getPattern().getNodes()) {
        pattern_node_num.get(act_id).put(node, new Integer(node_num++));
      }
      assert node_num == act.getPattern().getNodes().size()
          : "Wrong number of node_nums was created";

      // fill the map with pairs (edge, edge_num)
      int edge_num = 0;

      for (Edge edge : act.getPattern().getEdges()) {
        pattern_edge_num.get(act_id).put(edge, new Integer(edge_num++));
      }
      assert edge_num == act.getPattern().getEdges().size()
          : "Wrong number of edge_nums was created";

      // if action has a replacement graph, compute node/edge numbers
      if (act.getRight() != null) {
        replacement_node_num.set(act_id, new HashMap<Node, Integer>());
        replacement_edge_num.set(act_id, new HashMap<Edge, Integer>());

        // fill the map with pairs (node, node_num)
        node_num = 0;

        for (Node node : act.getRight().getNodes()) {
          replacement_node_num.get(act_id).put(node, new Integer(node_num++));
        }
        assert node_num == act.getRight().getNodes().size()
            : "Wrong number of node_nums was created";

        // fill the map with pairs (edge, edge_num)
        edge_num = 0;

        for (Edge edge : act.getRight().getEdges()) {
          replacement_edge_num.get(act_id).put(edge, new Integer(edge_num++));
        }
        assert edge_num == act.getRight().getEdges().size()
            : "Wrong number of edge_nums was created";
      } else {
        replacement_node_num.set(act_id, null);
        replacement_edge_num.set(act_id, null);
      }
    }

    /* for all actions decompose the conditions into conjunctive parts,
    give all these subexpessions a number, and setup some maps keeping
    information about them */
    // init a subexpression counter
    int subConditionCounter = 0;

    // setup the array for conditions
    conditions = new HashMap<Integer, Collection<Expression>>();

    // iterate over all actions
    for (Rule act : actionRuleMap.keySet()) {
      int act_id = actionRuleMap.get(act).intValue();

      conditions.put(act_id, new TreeSet<Expression>(conditionsComparator));

      // iterate over all conditions of the current action
      for (Expression condition : act.getPattern().getConditions()) {

        // divide the expression to all AND-connected parts, which do
        // not have an AND-Operator as root themselves
        Collection<Expression> subConditions = decomposeAndParts(condition);

        // for all the subconditions just computed...
        for (Expression sub_condition : subConditions) {

          // ...create condition numbers
          conditionNumbers.put(sub_condition, new Integer(subConditionCounter++));

          // ...extract the pattern nodes and edges involved in the condition
          Collection<Node> involvedNodes = collectInvolvedNodes(sub_condition);
          Collection<Edge> involvedEdges = collectInvolvedEdges(sub_condition);
          // and at these Collections to prepared Maps
          conditionsInvolvedNodes.put(sub_condition, involvedNodes);
          conditionsInvolvedEdges.put(sub_condition, involvedEdges);

          // store the subcondition in an ordered Collection
          conditions.get(act_id).add(sub_condition);
        }
      }
    }
    // store the overall number of (sub)conditions
    n_conditions = subConditionCounter;

    /* collect the type constraints of the node of all actions pattern graphs */
    int typeConditionCounter = n_conditions;
    typeConditions = new Vector<Collection<Collection<InheritanceType>>>(n_graph_actions);

    for (Rule act : actionRuleMap.keySet()) {
      int act_id = actionRuleMap.get(act).intValue();

      typeConditions.set(
          act_id, new TreeSet<Collection<InheritanceType>>(typeConditionsComparator));

      /* for all nodes of the current MatchingActions pattern graph
      extract that nodes type constraints */
      PatternGraph pattern = act.getPattern();
      for (Node node : pattern.getNodes()) {
        // if node has type constraints, register the as conditions
        if (!node.getConstraints().isEmpty()) {

          // note that a type condition is the set of all types,
          // the corresponding node/edge is not allowed to be of
          Collection<InheritanceType> type_condition = node.getConstraints();

          // ...create condition numbers
          typeConditionNumbers.put(type_condition, new Integer(typeConditionCounter++));

          // ...extract the pattern nodes and edges involved in the condition
          Collection<Node> involvedNodes = new HashSet<Node>();
          involvedNodes.add(node);
          // and at these Collections to prepared Maps
          typeConditionsInvolvedNodes.put(type_condition, involvedNodes);
          Collection<Edge> empty = Collections.emptySet();
          typeConditionsInvolvedEdges.put(type_condition, empty);

          // store the subcondition in an ordered Collection
          typeConditions.get(act_id).add(type_condition);
        }
      }
      // do the same thing for all edges of the current pattern
      for (Edge edge : pattern.getEdges()) {

        // if node has type constraints, register the as conditions
        if (!edge.getConstraints().isEmpty()) {

          // note that a type condition is the set of all types,
          // the corresponding edge is not allowed to be of
          Collection<InheritanceType> type_condition = edge.getConstraints();

          // ...create condition numbers
          typeConditionNumbers.put(type_condition, new Integer(typeConditionCounter++));

          // ...extract the pattern edges and edges involved in the condition
          Collection<Edge> involvedEdges = new HashSet<Edge>();
          involvedEdges.add(edge);
          // and at these Collections to prepared Maps
          Collection<Node> empty = Collections.emptySet();
          typeConditionsInvolvedNodes.put(type_condition, empty);
          typeConditionsInvolvedEdges.put(type_condition, involvedEdges);

          // store the subcondition in an ordered Collection
          typeConditions.get(act_id).add(type_condition);
        }
      }
    }
    // update the overall number of conditions, such that type
    // conditions are also included
    n_conditions = typeConditionCounter;

    /* for all conditions (not type conditions!) the pairs
    (pattern_node_num, attr_id), which occur
    in qualifications at the leaves of the condition, are needed.
    To obtain that compute a map
    condition_num -> pattern_node_num_ -> { attr_ids }
    implemented by an Array of Maps; usage is:
    involvedPatternNodeAttrIds[cond_num].get(pattern_node_num)
    which yields a Collection of attr-ids.
    */
    involvedPatternNodeAttrIds = new HashMap<Expression, Map<Node, Collection<Integer>>>();
    involvedPatternEdgeAttrIds = new HashMap<Expression, Map<Edge, Collection<Integer>>>();

    for (Rule act : actionRuleMap.keySet()) {
      int act_id = actionRuleMap.get(act).intValue();

      // collect the attr ids in dependency of condition and the pattern node
      for (Expression cond : conditions.get(act_id)) {
        // TODO use or remove it
        // int cond_num = conditionNumbers.get(cond).intValue();

        // descent to the conditions leaves and look for qualifications
        Map<Node, Collection<Integer>> node_map = new HashMap<Node, Collection<Integer>>();
        Map<Edge, Collection<Integer>> edge_map = new HashMap<Edge, Collection<Integer>>();
        __recursive_qual_collect(act_id, node_map, edge_map, cond);
        involvedPatternNodeAttrIds.put(cond, node_map);
        involvedPatternEdgeAttrIds.put(cond, edge_map);
      }
    }

    /* for each action compute the start node used in the matching process */
    // init the array of start nodes
    start_node = new Node[n_graph_actions];
    // for all actions gen matcher programs
    for (Rule action : actionRuleMap.keySet()) {
      Graph pattern = action.getPattern();

      // pick out the node with the highest priority as start node
      int max_prio = 0;
      // get any node as initial node
      Node max_prio_node = null;
      if (pattern.getNodes().iterator().hasNext()) {
        max_prio_node = pattern.getNodes().iterator().next();
      }
      for (Node node : pattern.getNodes()) {
        // get the nodes priority
        int prio = 0;
        Annotations a = node.getAnnotations();
        if (a != null)
          if (a.containsKey("prio") && a.isInteger("prio"))
            prio = ((Integer) a.get("prio")).intValue();

        // if the current priority is greater, update the maximum priority node
        if (prio > max_prio) {
          max_prio = prio;
          max_prio_node = node;
        }
      }
      start_node[actionRuleMap.get(action).intValue()] = max_prio_node;
    }
    // collect information about potential homomorphic pattern graph nodes,
    // i.e. nodes that are allowed to be identified by the matcher during the
    // matching process
    collectPotHomInfo();
    collectPatternNodesToBeKeptInfo();
    collectReplacementNodeIsPreservedNodeInfo();
    collectReplacementNodeChangesTypeToInfo();
    collectNewInsertEdgesInfo();
  }