/*
 * Copyright 2003-2011 JetBrains s.r.o.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package jetbrains.mps.make.dependencies.graph;

import jetbrains.mps.util.GraphUtil;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

public class Graphs {
  public static int[][] graphToIntInt(IVertex[] vertices, boolean allowSelfLoops, boolean sorted) {
    int count = vertices.length;
    int[] temparray = new int[count];
    int[][] result = new int[count][];

    Map<IVertex, Integer> rootIndex = new LinkedHashMap<IVertex, Integer>(vertices.length);
    for (int i = 0; i < vertices.length; i++) {
      rootIndex.put(vertices[i], i);
    }

    for (int index = 0; index < count; index++) {
      IVertex vertex = vertices[index];
      int tsize = 0;
      for (IVertex node : vertex.getNexts()) {
        Integer targetIndex = rootIndex.get(node);
        if (targetIndex != null && (allowSelfLoops || targetIndex != index)) {
          temparray[tsize++] = targetIndex;
        }
      }
      result[index] = new int[tsize];
      if (tsize > 0) {
        System.arraycopy(temparray, 0, result[index], 0, tsize);
      }
    }
    if (sorted) {
      GraphUtil.sort(result);
    }
    return result;
  }


  /**
   * @return strongly connected components in the topological order
   */
  public static <V extends IVertex> List<List<V>> findStronglyConnectedComponents(Graph<V> graph0) {
    IVertex[] vertices = graph0.getData().toArray(new IVertex[graph0.getNVertexes()]);
    int[][] graph = graphToIntInt(vertices, false, false);
    int[][] partitions = GraphUtil.tarjan(graph);

    List<List<V>> result = new ArrayList<List<V>>(partitions.length + 1);
    for (int i = partitions.length - 1; i >= 0; i--) {
      List<V> proots = new ArrayList<V>(partitions[i].length);
      for (int e = 0; e < partitions[i].length; e++) {
        proots.add((V) vertices[partitions[i][e]]);
      }
      result.add(proots);
    }
    return result;
  }
}
