package com.orionplatform.math.graph.tasks.check;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.IntStream;
import com.orionplatform.core.abstraction.Orion;
import com.orionplatform.math.combinatorics.permutations.PermutationService;
import com.orionplatform.math.graph.Graph;
import com.orionplatform.math.graph.GraphRules;
import com.orionplatform.math.linearalgebra.matrix.Matrix;
import com.orionplatform.math.number.ANumber;

public class AreGraphsIsomorphicTask extends Orion
{
    @SuppressWarnings("unchecked")
    public static synchronized boolean run(Graph graph, Graph other)
    {
        GraphRules.doGraphsHaveSameNumberOfVertices(graph, other);
        Matrix adjacencyMatrixOfGraph = graph.getAdjacencyMatrix();
        Matrix adjacencyMatrixOfOther = other.getAdjacencyMatrix();
        
        if(adjacencyMatrixOfGraph.equals(adjacencyMatrixOfOther))
        {
            return true;
        }
        else
        {
            List<Integer> objectsToPermute = new ArrayList<>();
            IntStream.range(0, adjacencyMatrixOfGraph.getNumberOfRows()).forEach(i -> objectsToPermute.add(i));
            List<List<?>> permutationsOfrows = PermutationService.permute(objectsToPermute);
            
            for(List<?> permutationOfRows : permutationsOfrows)
            {                
                List<Integer> permutations = (List<Integer>)permutationOfRows;
                ANumber[][] newElements = new ANumber[permutations.size()][permutations.size()];
                
                for(int i = 0; i < permutations.size(); i++)
                {
                    for(int j = 0; j < permutations.size(); j++)
                    {
                        newElements[i][j] = adjacencyMatrixOfGraph.get(permutations.indexOf(i), permutations.indexOf(j));
                    }
                }
                
                if(Matrix.of(newElements).equals(adjacencyMatrixOfOther))
                {
                    return true;
                }
            }
        }
        
        return false;
    }
}